自学内容网 自学内容网

SwiftData 模型对象的多个实例在 SwiftUI 中不能及时同步的解决

在这里插入图片描述

概览

我们已经知道,用 CoreData 在背后默默支持的 SwiftUI 视图在使用 @FetchRequest 来查询托管对象集合时,若查询结果中的托管对象在别处被改变将不会在 FetchedResults 中得到及时的刷新。

在这里插入图片描述

那么这一“囧境”在 SwiftData 里是否也会“卷土重来”呢?空说无益,就让我们在这里来一场钩深索隐、推本溯源的探究之旅吧。

相信学完本课后,小伙伴们一定会惊叹在 SwiftData 模型对象多个实例间的同步竟如此之简单,简直不可思议!

无需等待,让我们马上开始同步大冒险吧!Let’s go!!!😉


1. CoreData 托管对象多个实例的同步问题

我们知道为了和 SwiftUI “亲密无间”,何曾几时(iOS 13.0+) CoreData 的托管类 NSManagedObject 也悄然遵守了 ObservableObject 协议。

在这里插入图片描述

从那一刻起,CoreData 托管对象便可以乖巧的作为 SwiftUI 视图中的状态“乐此不疲”。

在这里插入图片描述

不过,在 SwiftUI 视图 @FetchRequest 查询结果 FetchedResults 中的托管对象若在外部被修改,则该查询结果并不会自动进行同步:

@FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Cave.name, ascending: false)], predicate: NSPredicate(format: "challenge.stateValue = \(ChallengeState.inProgress.rawValue)"), animation: .bouncy) var inProcessingCaves: FetchedResults<Cave>

拿上面的 inProcessingCaves 状态来说,它包括了所有正在“进行中”的 Cave 托管对象(用 NSPredicate 来过滤数据),这些对象都会显示在主视图顶部“正在进行”的 Section 里:

在这里插入图片描述

如果我们在子视图里将 inProcessingCaves 中的任何对象状态由“进行中”改成了“已失败”,那么它们理应从“正在进行”的 Section 中“销声匿迹”,但实际情况却事与愿违:

在这里插入图片描述

如上图所示:红色的“已失败”Cave 托管对象仍在“厚颜无耻”的占据着“正在进行” Section 中的宝贵空间。


关于上面 CoreData 中 @FetchRequest 托管对象的过滤结果不能被及时刷新的解决之道,我们将会在后续博文中详述,小伙伴们敬请期待吧!


那么这种情况在最新的 SwiftData 中还会存在吗?让我们探寻一番吧。

2. SwiftData 是否会重蹈覆辙?

SwiftData 是苹果在 WWDC 23 推出的完全符合 Swift 范儿的数据库框架,其描述性的语法非常适合托管表本身、表字段以及表间关系的构建。


更多 SwiftData 相关内容的介绍,请小伙伴们尽情观赏如下链接中的精彩内容:


为了模拟 CoreData 中的数据结构,我们分别创建了两个 SwiftData 数据模型:Item 和 SubItem,其中每个 Item 都至多包含一个 SubItem。

import SwiftData

@Model
final class Item {
   
    @Attribute(.unique) var id: UUID
    var timestamp: Date
    var name: String
    
    @Relationship
    var subItem: SubItem?
    
    init(timestamp: Date, name: String) {
   
        self.timestamp = timestamp
        self.name = name
        id = UUID()
    }
    
    static var sampleItems: [Item] = {
   
        var items = [Item]()
        let names = ["Apple", "Jujube", "Watermelon"]
        for name in names {
   
            let new = Item(timestamp: Date.now, name: name)
            let newSub = SubItem(timestamp: Date.now, name: "Sub \(name)", state: .unstarted)
       

原文地址:https://blog.csdn.net/mydo/article/details/140240773

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!