🔨

SwiftDataでネストされた子Modelにアクセスするとクラッシュする

2023/12/10に公開

はじめに

クラッシュが発生する状況をMinimumのコードで再現しました。

SwiftDataでModelが入れ子状態になっている。@Relationshipも適切に設定されているが、子Modelにアクセスをするとクラッシュが発生。

import SwiftUI
import SwiftData

@main
struct SwiftDataDemoApp: App {
    var body: some Scene {
        WindowGroup {
            Text("Hello, world!")
                .modelContainer(for: Parent.self)
                .onAppear {
                    let parent = Parent()
                    let child = Child()
                                        
                    parent.children.append(child)
                    print("parent name: \(parent.name)")
                    
                    parent.children.forEach { child in
                        print("child name:\(child.name)") // CRASH: EXC_BREAKPOINT
                    }
                }
        }
    }
}

@Model final class Parent {
    var name = "mom"
    @Relationship(deleteRule: .cascade, inverse: \Child.parent) 
    var children: [Child] = []
    
    init() {}
}

@Model final class Child {
    var parent: Parent?
    var name: String = "son"
    
    init() {}
}

実行するとこのようにParentのGetterにある_$observationRegistrar.accessでCrashが発生します。

Solution

ModelContextに親Modelをinsertしておき、子Modelにはそのあとでアクセスする。

@main
struct SwiftDataDemoApp: App {
    let container = try! ModelContainer(for: Parent.self)
    var body: some Scene {
        WindowGroup {
            Text("Hello, world!")
                .modelContainer(container)
                .onAppear {
                    let parent = Parent()
                    let child = Child()
                    
                    // modelContextに親Modelをinsert
                    let context = container.mainContext
                    context.insert(parent)
                                        
                    parent.children.append(child)
                    print("parent name: \(parent.name)")
                    
                    parent.children.forEach { child in
                        print("child name:\(child.name)")
                    }
                }
        }
    }
}

Discussion