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で保存する。