You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中PreviewProvider无法正确加载CoreData关联视图变量

解决CoreData中Session与Climb关联在预览中不生效的问题

问题根源

  • CoreData关系赋值方式错误:Session的climbs属性在CoreData中实际是NSSet?类型(而非Swift数组),直接赋值[climbOne, climbTwo]无法正确建立关联。
  • 预览中未保存上下文:创建完CoreData对象后没有调用save(),导致对象关系未被持久化,预览无法读取到关联数据。
  • 预览上下文不统一:闭包内创建了一个独立的PersistenceController(inMemory: true),但视图又使用了PersistenceController.preview的上下文,两者不匹配。

解决方案

1. 修正Session与Climb的关联方式

CoreData为一对多关系自动生成了addTo<RelationshipName>()方法,用这个方法来添加关联对象:

let session: Session = Session(context: viewContext)
session.addToClimbs(climbOne)
session.addToClimbs(climbTwo)

如果偏好数组赋值,需要将Swift数组转换为NSSet:

session.climbs = NSSet(array: [climbOne, climbTwo])

2. 保存预览上下文

在返回session之前,必须保存上下文,确保对象关系被持久化:

do {
    try viewContext.save()
} catch {
    let nsError = error as NSError
    fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}

3. 统一预览上下文

闭包内创建的PersistenceController要和视图使用的保持一致,直接复用PersistenceController.preview的上下文即可:

struct SessionDetailView_Previews: PreviewProvider {
    static var previews: some View {
        let viewContext = PersistenceController.preview.container.viewContext
        
        let climbOne: Climb = Climb(context: viewContext)
        climbOne.grade = 2
        climbOne.attempts = 1
        climbOne.sent = true
        climbOne.timestamp = Date()
        
        let climbTwo: Climb = Climb(context: viewContext)
        climbTwo.grade = 5
        climbTwo.attempts = 4
        climbTwo.sent = true
        climbTwo.timestamp = Date()
        
        let session: Session = Session(context: viewContext)
        session.addToClimbs(climbOne)
        session.addToClimbs(climbTwo)
        
        do {
            try viewContext.save()
        } catch {
            fatalError("Preview save failed: \(error.localizedDescription)")
        }
        
        return SessionDetailView(session: session)
            .environment(\.managedObjectContext, viewContext)
    }
}

4. 优化climbArray扩展(可选)

原扩展逻辑可行,但可以避免强制解包timestamp,提升代码安全性:

extension Session {
    public var climbArray: [Climb] {
        let set = climbs as? Set<Climb> ?? []
        return set.sorted {
            guard let ts1 = $0.timestamp, let ts2 = $1.timestamp else {
                return false
            }
            return ts1 < ts2
        }
    }
}

内容的提问来源于stack exchange,提问作者stackiee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 13:53:25