[Swift] 34 メモアプリ製作 その10 NSMergeConflict対策

[M1 Mac, Ventura 13.3.1, Xcode 14.3]

メモアプリのメモを追加し、アプリを再起動させてから削除しようとすると1回目は必ずエラーになっていました。

エラーメッセージではNSMergeConflictとなっていてCore Dataの不一致が起こっているようでした。ネットでは類似の情報は見当たらず、試しに削除後すぐにviewContextをリフレッシュしてから保存するようにコードを書き換えると上手くいきました。

他言語ではありますが、UIに関するコードをこれまで散々書いてきた経験が活きた格好です。深みにハマらなくて助かりました。

func deleteContent(offsets:IndexSet){
        for offset in offsets{
            print("offset:\(offset)")
            viewContext.delete(contents[offset])
        }

        // Core Data(Data Model)を更新
        viewContext.refreshAllObjects() // この行を追加して解決

        do {
            try viewContext.save()
        } catch let error as NSError {
            fatalError("セーブ失敗: \(error), \(error.userInfo)")
        }
    }

[Swift] 32 ChatGPTアプリ製作 その3 指示文のソート

[M1 Mac, Ventura 13.3.1, Xcode 14.3]

指示文が連続する会話形式ではデータをJSONファイルにするなど保存するデータがややこしくなるため、一問一答形式でブラッシュアップしました。

指示文が作成順にうまく並ばないので、EntityのAttributeに生成日時を追加しこれをキーとしてソートさせています。常に先頭の指示文を送信する仕様になっています。

また、指示済かつ回答受信済の内容については送信ボタンを押すとアラートが表示されます。

保存するデータがEntityの形式に縛られるのが何とももどかしいです。JSONファイルとしてiCloudやローカルに出力できないか調べてみます。

これで土台はできあがったので、後はのんびり進めていきます。気が向いたら会話形式にも着手します。

アラート表示
import SwiftUI
import CoreData

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(
        entity: Interaction.entity(),
        sortDescriptors: [NSSortDescriptor(key: "creationDate", ascending: false)])
    private var pairs: FetchedResults<Interaction>

    @State var isShowAlert = false

    var body: some View {
        NavigationView {
            VStack{
                List {
                    ForEach(pairs) { pair in
                        NavigationLink{
                            if((pair.instruction?.isEmpty) == false){
                                Draft(text:pair.instruction!, interaction: pair)
                            }
                        }
                        label:{
                            if((pair.instruction?.isEmpty) == false){
                                Text(pair.instruction!)
                            }
                        }
                    }

                    .onDelete(perform: deleteInteraction)
                }
                .navigationTitle("ChatGPTSwift")
                .navigationBarTitleDisplayMode(.inline)
                .toolbar{
                    // 新規作成
                    ToolbarItem(placement:.navigationBarTrailing){
                        NavigationLink{
                            Draft()
                        }label:{
                            Text("+")
                                .font(.system(size: 30))
                        }
                    }
                }

                List {
                    ForEach(pairs, id: \.self) { pair in
                        if let res = pair.res , !res.isEmpty {
                            Text(res)
                            .foregroundColor(.white)
                            .background(Color.blue)
                        }
                    }


                    .onDelete(perform: deleteInteraction)
                }

                Button(action:{
                    if pairs.first != nil{
                        let instruction = pairs.first
                        
                        if instruction!.res == nil{
                            sendRequest(pairs:pairs)
                        }else{
                            isShowAlert = true
                            print("指示文を入力して下さい")
                        }
                        
                    }else{
                        print("pairsは空です")
                        
                    }
                }){
                    Text("送信")
                    .font(.system(size: 24))
                }
                .alert("指示文を入力して下さい", isPresented: $isShowAlert) {
                    Button("OK") {
                    }
                } message: {
                    Text("")
                }
            }
        }
    }
<以下略>
Core Data(Data Model)の内容
creationDateを追加