Jsonの読み書きをCodableで簡単に

ちょっとしたコードや設定などですが、忘れがちであらためて調べるのも面倒なので、忘備録的なものです。
順不同で、気づいたものから順にSwift4で使えるコードを載せていきます。

Swift-Tips

Jsonの読み書きをCodableで簡単に

swift4ではCodableを利用することでJsonファイルの読み書きが簡単になりました。

jsonDecoderでJsonファイルのデータを構造体に読み出し
・Codableな構造体を定義しておくこと(通常の構造体にCodable宣言を付加するだけ)
・おまけ:texts配列をCSVに変換する関数texts2CSV()
・初期状態では読み出し元ファイルがないのでデフォルトの設定から作る
・Audioフォルダに音声ファイルを管理するJsonの例

構造体の定義


// Jsonファイルから読み出したデータを保存する構造体 // 構造体内のtexts配列をCSVに変換する関数texts2CSV() struct Entry: Codable { var date:Date var title:String var memo:String var audioFilePath:String var audioFileName:String var texts:[TextPhrase] /// カンマ区切りの文字列に変換 func texts2CSV() -> String { var rtnStr = "" for i in 0 ..< texts.count { let time:String = "\"" + texts[i].time2hhmmss() + "\",\"" let speaker:String = texts[i].speaker + "\",\"" rtnStr += time + speaker + texts[i].text + "\"\r\n" } return rtnStr } } // Jsonファイルから読み出したデータを保存する構造体 // 配列の中身の構造体もCodableで定義しておく // 構造体内のtopの時間をhh:mm:ssに変換する関数time2hhmmss() struct TextPhrase: Codable { var top:TimeInterval var end:TimeInterval? var speaker:String var text:String var comment:String func time2hhmmss() -> String { let formatter = DateComponentsFormatter() formatter.unitsStyle = .positional formatter.allowedUnits = [.minute,.hour,.second] formatter.zeroFormattingBehavior = .pad return formatter.string(from: top) ?? "" } }

読み書きするjsonはこんな感じ


[ { "memo" : "", "title" : "このアプリの使い方", "audioFileName" : "sample.mp3", "texts" : [ { "speaker" : "編集部", "top" : 0, "end" : 7.0, "comment" : "Repeat After YOU!", "text" : "このアプリは文字起こしを超高速に行うことに特化したアプリです。" }, { "speaker" : "編集部", "top" : 7.0, "end" : 18.0, "comment" : "", "text" : "録音音声から聞き取った内容を、オウム返しで話して音声認識させることで、キーボードを使わずに超高速に文字起こしができます。" } ], "audioFilePath" : "sample.mp3", "date" : 531674816.56146502 } ]

Jsonの読み出し


var entries: [Entry] = [] func readSavedJson() { let jsonPath = liblaryPath + "/" + jsonFileName // jsonをファイルから読み出す let fm = FileManager() let jsonDecoder = JSONDecoder() let jsonStr:String // ファイルの有無をチェック if fm.fileExists(atPath: jsonPath) { do { jsonStr = try String(contentsOfFile: jsonPath, encoding: .utf8) } catch _ { return } } else { print("No File : \(jsonPath)") //entries = [] // 初期状態では何もないのでリソースから作る if let assetJson = NSDataAsset(name: "originJson") { jsonStr = String(data: assetJson.data, encoding: .utf8) ?? "" // サンプルファイルをAudioフォルダにコピー if let assetAudio = NSDataAsset(name: "sampleAudio") { let audioData = assetAudio.data as NSData let audioFilePath = documentsPath + "/Audio/sample.mp3" let audioFolderPath = documentsPath + "/Audio" //Audioフォルダが無ければ作る var isDirExists : ObjCBool = false fm.fileExists(atPath: audioFolderPath, isDirectory:&isDirExists) if !isDirExists.boolValue { do { try fm.createDirectory(atPath: audioFolderPath, withIntermediateDirectories: true, attributes: nil) } catch let error1 { print("Error createDirectory : \(audioFolderPath) : " + error1.localizedDescription ) return } } // ファイルを書き込む audioData.write(toFile: audioFilePath, atomically: true) } } else { entries = [Entry(date:Date(),title:"No Date",memo:"",audioFilePath:"NoAudio.mp4",audioFileName:"NoAudio.mp4",texts:[TextPhrase(top:0,end:nil,speaker:"No One",text:"say something",comment:"no comment")])] return } } entries = try! jsonDecoder.decode([Entry].self, from: jsonStr.data(using: .utf8)!) }

Jsonの書き込み

JSONEncoderで構造体をエンコードして書き込み
・構造体は上で定義したもの


func saveEntriesToJson() { let jsonPath = liblaryPath + "/" + jsonFileName let jsonEncoder = JSONEncoder() jsonEncoder.outputFormatting = .prettyPrinted let data = try! jsonEncoder.encode(entries) let dataStr = String(data:data,encoding:.utf8) if dataStr?.isEmpty ?? true { return } do { // Stringデータをファイルに書き出し try dataStr!.write(toFile: jsonPath, atomically: true, encoding: .utf8) } catch _ { print("Write Error! File : \(jsonPath)") } }