当前位置: 首页 > article >正文

SwiftUI 在 Xcode 预览修改视图 FetchedResults 对象的属性时为什么会崩溃?

在这里插入图片描述

概览

从 SwiftUI 诞生那天起,让秃头码农们又爱又恨的 Xcode 预览就在界面调试中扮演了及其重要的角色。不过,就是这位撸码中的绝对主角却尝尝在关键时刻“掉链子”。

在这里插入图片描述

比如当修改 SwiftUI 视图中 FetchedResults 对象的属性时,Xcode 预览可能会毫不留情的发生崩溃。这是怎么回事,又该如何解决呢?

在本篇博文中,您将学到如下内容:

  • 概览
  • 1. 莫名其妙的崩溃场景
  • 2. 崩溃的根本原因
  • 总结

本篇博文代码测试环境:macOS 15.2 + Xcode 16.1

相信学完本课后,小伙伴们对于 Xcode 预览中 SwiftUI 视图 FetchedResults 对象的领悟又会更加精进一层!

那还等什么呢?Let‘s go!!!😉


1. 莫名其妙的崩溃场景

在 SwiftUI 与 CoreData 共同协作的视图中,我们常常需要使用 @FetchRequest 属性包装器来获取所有相关的托管对象:

struct MainTest: View {    
    @FetchRequest(sortDescriptors: [.init(keyPath: \WorryObject.name, ascending: false)], animation: .bouncy) var allWorryObjects: FetchedResults<WorryObject>
    
    @State var ascending = false
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(allWorryObjects) { wObj in
                    VStack(alignment: .leading) {
                        Label(wObj.name ?? "", systemImage: "brain.filled.head.profile")
                            .font(.title2)
                        Text(wObj.desc ?? "")
                            .foregroundStyle(.gray)
                    }
                }
            }
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button(ascending ? "升序" : "降序") {
                        ascending.toggle()
                    }
                }
            }
            .onChange(of: ascending) {_,new in
                allWorryObjects.nsSortDescriptors = [.init(keyPath: \WorryObject.name, ascending: ascending)]
            }
        }
    }
}

#Preview {
    let context = Common.moc_auto

    MainTest()
        .task {
            try! WorryObject.createDefaults(context)
        }
}

我们在上面的代码中主要做了这样几件事:

  • 使用 @FetchRequest 属性包装器产生结果为 FetchedResults<WorryObject> 的托管对象集合;
  • 遍历每个 WorryObject 对象并在视图中显示它们;
  • 让用户通过 ascending 状态切换 allWorryObjects 集合的排序方式,这是利用动态修改 FetchedResults<WorryObject> 的 nsSortDescriptors 属性来实现的;

不过,上面这段代码在 Xcode 预览中会有两个问题:

  1. 我们的 WorryObject.createDefaults() 方法明明产生了若干默认 WorryObject 对象,但在预览视图中却依旧是一片“空白”;
  2. 当我们切换 allWorryObjects 集合的排序方式时,预览会立即崩溃;

在这里插入图片描述

从预览崩溃栈中我们可以发现,崩溃的原因是重新设置 FetchedResults<WorryObject> 对象的 nsSortDescriptors 属性的操作所导致的:

在这里插入图片描述

然而奇怪的是,完全相同的代码在模拟器和真机上却毫无任何问题:

在这里插入图片描述

为什么单单 Xcode 预览会如此蛋疼呢?

2. 崩溃的根本原因

其实 Xcode Preview 榱崩栋折的原因很简单,我们也在之前很多篇博文详细讨论过了。

简单来说,在 Xcode 预览环境中 SwiftUI 视图若包含 @FetchRequest 属性包装器,则必须向视图传递正确的 managedObjectContext 环境变量。而且该环境变量必须特别针对预览做出修正。


关于在 Xcode 预览中向 SwiftUI 视图传递 managedObjectContext 环境变量导致的其它问题,请小伙伴们移步如下链接观赏进一步精彩的内容:

  • 向 SwiftUI 视图注入 managedObjectContext 环境变量导致 Xcode 预览(Preview)崩溃的解决
  • SwiftUI 视图 CoreData 的 @FetchRequest 请求结果在预览中无法自动刷新的解决之道

按照这种思路,我们可以很快写出修复方案:

struct MainTest: View {
    
    @Environment(\.managedObjectContext) var context
    @FetchRequest(sortDescriptors: [.init(keyPath: \WorryObject.name, ascending: false)], animation: .bouncy) var allWorryObjects: FetchedResults<WorryObject>
}

#Preview {
    let context = try! Common.moc_auto.cook4Preview(WorryObject.self)
    
    MainTest()
        .environment(\.managedObjectContext, context)
        .task {
            // 创建默认 WorryObject 对象集合
            try! WorryObject.createDefaults(context)
        }
}

在上面的代码中,我们向 MainTest 视图传递了修复后的托管对象上下文,这使得它在 Xcode 预览环境中表现的出类拔萃!棒棒哒!💯

在这里插入图片描述

至此,我们已经彻底了解了博文开头那个问题,并一发入魂给出完美的解决方案!么么哒!


想要进一步系统地学习 Swift 开发的小伙伴们,可以来我的《Swift 语言开发精讲》专栏逛一逛哦:

在这里插入图片描述

  • 《Swift 语言开发精讲》

总结

在本篇博文中,我们讨论了为何包含 FetchedResults 对象的 SwiftUI 视图属性被修改时,在 Xcode 预览中会导致崩溃。并在最后给出完美解决之道。

感谢观赏,再会啦!😎


http://www.kler.cn/a/531899.html

相关文章:

  • 分页按钮功能
  • Maven的三种项目打包方式——pom,jar,war的区别
  • LeetCode:53.最大子序和
  • DBASE DBF数据库文件解析
  • 双指针算法思想——OJ例题扩展算法解析思路
  • SSRF 漏洞利用 Redis 实战全解析:原理、攻击与防范
  • DRM系列七:Drm之CREATE_DUMB
  • C++(进阶) 第8章unordered_map和unordered_set的使⽤(哈希)
  • 基于STM32景区环境监测系统的设计与实现(论文+源码)
  • 分布式数据库架构与实践:原理、设计与优化
  • 3 卷积神经网络CNN
  • ES6 入门教程:箭头函数、解构赋值及其他新特性详解
  • Gurobi求解旅行商问题的官方例程
  • 计网week3
  • 【LeetCode 刷题】回溯算法(5)-棋盘问题
  • Linux线程 —— 生产消费模型
  • 存储器知识点3
  • 优选算法的灵动之章:双指针专题(一)
  • 算法设计-0-1背包动态规划(C++)
  • 4.[ISITDTU 2019]EasyPHP
  • Nginx笔记220825
  • 机器学习day7
  • 红黑树的封装
  • 680.验证回文串||
  • 基于“蘑菇书”的强化学习知识点(二):强化学习中基于策略(Policy-Based)和基于价值(Value-Based)方法的区别
  • Debezium Oracle Connector SCN处理优化指南