SwiftUIでCodableとIdentifiableの構造体を作る

SwiftUIで構造体の配列を作ってUserDefaultでデータ保存するパターンが多い。

その際に、UDを使うからCodableが必要だし、Listで一覧表示させたい場合には、Identifiableが必要になる。

しかし、やってみると結構面倒で、データ保存の際はCoreDataを使った方が楽だと感じた。

構造体と配列の定義

struct Record:Codable,Identifiable{
    let id:UUID
    var totalDay = 0
    var totalNum = 0
    var totalPrice = 0
    var PeriodString = ""
}

こんな感じ。idはIntでも良いけど、UUIDだと楽。

class ViewModel: ObservableObject {
    @Published var recordArray:[Record] = []

ViewModelの中で配列として作っておく。

データ読み出し

ViewModelのinitでUDから保存データをロードするようにすると良い。

    init(){
        loadRecord()
    }

    func loadRecord() {
        if let load = loadRC(){
            recordArray = load
        }
    }
    //読み込み
    func loadRC() -> [Record]? {
        let jsonDecoder = JSONDecoder()
        guard let data = UserDefaults.standard.data(forKey: rcKey),
              let hoge = try? jsonDecoder.decode([Record].self, from: data) else {
            return nil
        }
            
        return hoge
    }

データ保存

保存するときは構造体をインスタンス化して配列に追加する。

    func addRecord() {
        recordArray.append(Record(id: UUID(), totalDay: totalDay, totalNum: totalNum, totalPrice: totalPrice, PeriodString: period))
        saveRC(rc: recordArray)
    }

    func saveRC(rc: [Record]) {
        let jsonEncoder = JSONEncoder()
        guard let data = try? jsonEncoder.encode(rc) else {
            return
        }
        UserDefaults.standard.set(data, forKey: rcKey)
    }

Listで表示

struct LogView: View {
    @ObservedObject var vm:ViewModel
    var body: some View {
        if(!vm.recordArray.isEmpty){            
            List {
                ForEach(vm.recordArray) { rc in
                    OneRow(record: rc)
                }.onDelete(perform: delete)
            }
        }else{
            Text("データはありません。")
        }
    }
    func delete(at offsets: IndexSet) {
        vm.deleteRecord(at: offsets)
    }
}

Identifiableを継承して作った構造体の配列なので、List表示ができる。

削除する

    func deleteRecord(at offsets: IndexSet) {
        recordArray.remove(atOffsets: offsets)
        saveRC(rc: recordArray)
    }

Indexを指定して配列から削除し、UDで保存する。

ABOUTこの記事をかいた人

個人アプリ開発者。Python、Swift、Unityのことを発信します。月間2.5万PVブログ運営。 Twitter:@yamagablog