SwiftUI:从单元格视图中删除托管对象会使应用程序崩溃[非可选属性]?

2024-02-23

我发布了这个问题:

SwiftUI:从单元格视图中删除托管对象会使应用程序崩溃? https://stackoverflow.com/questions/73159270/swiftui-deleting-managed-object-from-cell-view-crashes-app

当我试图理解它崩溃的原因时,我尝试更改模型Item具有timestamp非可选:

extension Item {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Item> {
        return NSFetchRequest<Item>(entityName: "Item")
    }

    @NSManaged public var timestamp: Date

}

extension Item : Identifiable {

}

正如 Asperi 指出的,使用这个:

  if let timestamp = item.timestamp {
    Text(timestamp, formatter: itemFormatter)
  }

确实修复了崩溃时timestamp是可选的。

然而,这只是我正在测试的一些代码,以了解如何正确构建我的视图。我需要使用没有可选属性的模型,因此我无法使用为上面链接的问题提供的答案。

所以这个问题是为了解决我的情况CellView使用的属性是不可选在托管对象上。

如果我把这段代码直接放在ContentView不使用CellView它不会崩溃。这不会崩溃:

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

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults<Item>

    var body: some View {
        NavigationView {
            List {
                ForEach(items) { item in
                    NavigationLink {
                        Text(item.timestamp, formatter: itemFormatter)
                    } label: {
//                        CellView(item: item)
                        HStack {
                            Text(item.timestamp, formatter: itemFormatter) // <<- CRASH ON DELETE
                            Button {
                                withAnimation {
                                    viewContext.delete(item)
                                    try? viewContext.save()
                                }
                                
                            } label: {
                                Text("DELETE")
                                    .foregroundColor(.red)
                            }
                            .buttonStyle(.borderless)
                        }
                    }
                }
                .onDelete(perform: deleteItems)
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
            Text("Select an item")
        }
    }

    private func addItem() {
        withAnimation {
            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()

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

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            offsets.map { items[$0] }.forEach { item in
                viewContext.delete(item)
            }

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

但是,我需要知道如何保持CellView, use @ObservedObject并使这项工作成功。在这种情况下,这样做没什么大不了的,但在实际情况下,CellView更大时,这种方法不能很好地扩展。无论如何,为什么要使用@ObservedObject单独来看是错的吗?

那么,为什么应用程序崩溃时timestamp模型中不是可选的吗? 为什么视图试图为已删除的项目重绘 CellView ?如何解决这个问题?

为了清楚起见,我在此处发布了非可选案例的新代码,因此您不必返回并查看链接的问题,然后将其更改为非可选。这是整个崩溃的代码:

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

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults<Item>

    var body: some View {
        NavigationView {
            List {
                ForEach(items) { item in
                    NavigationLink {
                        Text(item.timestamp, formatter: itemFormatter)
                    } label: {
                        CellView(item: item)
                    }
                }
                .onDelete(perform: deleteItems)
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
            Text("Select an item")
        }
    }

    private func addItem() {
        withAnimation {
            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()

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

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            offsets.map { items[$0] }.forEach { item in
                viewContext.delete(item)
            }

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

struct CellView: View {
    
    @Environment(\.managedObjectContext) private var viewContext
    @ObservedObject var item:Item
    
    var body: some View {
        
        HStack {
            
            Text(item.timestamp, formatter: itemFormatter) // <<- CRASH ON DELETE
            
            Button {
                withAnimation {
                    viewContext.delete(item)
                    try? viewContext.save()
                }
                
            } label: {
                Text("DELETE")
                    .foregroundColor(.red)
            }
            .buttonStyle(.borderless)
        }
        
    }
    
}

private let itemFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    formatter.timeStyle = .medium
    return formatter
}()

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
    }
}

由于 CoreData 引擎的特殊性,无论如何都需要显式处理。对象删除后,它仍然可以在内存中(由于保留引用),但它会处于错误状态,这就是为什么代码自动生成总是将 NSManagedObject 属性设置为可选(即使它们在模型中不是可选的)。

这是针对此特定情况的修复。使用 Xcode 13.4 / iOS 15.5 进行测试

if !item.isFault {
    Text(item.timestamp, formatter: itemFormatter) // << NO CRASH
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SwiftUI:从单元格视图中删除托管对象会使应用程序崩溃[非可选属性]? 的相关文章

  • HTML 5 + iOS - 创建混合应用程序

    我正在尝试将我的本机 iOS 应用程序转换为使用 HTML 5 的混合应用程序 经过研究后我最终得到了jQuery 移动 phoneGap 我的问题是 是否可以将 html 5 和本机 iOS 功能混合在一个单一的版本中 看法 例如我可以使
  • 强制变量声明的协议 - Objective C

    是否可以在 protocol中声明变量 只是为了强制程序员在实现类 实现此协议的类 标头和实现中添加这些变量 Thanks 简短回答 不 不可能那样做 您最多可以强制方法和属性的可用性
  • 更新 iOS 应用程序的应用内购买内容?

    我似乎无法在任何地方找到这个问题的答案 所以这里 我正在开发一个 iOS 应用程序 该应用程序将具有非消耗性应用内购买 扩展包 例如 假设我出售一个包含 10 个级别的包 并且在一个月内我想将应用内购买更新为包含 15 个级别 用户无需重新
  • 将 swift 结构体转换为 json 字符串

    我正在尝试将我的 swift 结构转换为 json 格式 类似这样的问题似乎有不少 但到目前为止 没有一个解决方案对我有用 这是我的结构 struct Rec Codable var name String var time Int var
  • 类型名称已知却未知?

    Xcode 突然显示了此错误 未知类型名称 我会解释一下 我的 StoriesViewController h import
  • 如何开发iPhone MDM服务器?

    我刚刚阅读了有关适用于 iOS 设备的移动设备管理服务器的信息 但所有文档均指 第三方 MDM 服务器 我的问题是如何自己开发一个 第三方 MDM 服务器 我找不到任何关于此的文档 你有简单的方法和困难的方法 Easy way OSX Li
  • 从电话号码确定国际电话代码的算法

    我可以使用 iOS 上的地址簿框架从设备中检索联系人的电话号码 如何区分或识别哪个是国家 地区代码 哪个是实际电话号码 是否可以 国家 地区代码是一个相当混乱的主题 但足够标准 通过一些程序员维护就可以解决它 您可以通过其初始子序列来识别国
  • 在 flutter 应用程序中添加启动屏幕的正确方法是什么?

    我正在开发一个基于 flutter 的应用程序 并研究了几种添加闪屏的方法 但我不确定哪一个是最好实现的 import dart async import package flutter material dart import packa
  • Swift 中的条件导入

    我有一个在各种应用程序中使用的日志功能 由于我在整个应用程序中使用它 因此也可以方便地进行 Crashlytics 日志记录调用 然而 并非每个应用程序都使用 Crashlytics 在 Objective C 中 您可以使用预处理器条件来
  • 如何在 iOS 中以编程方式在 UITableViewCells 中添加图像

    我需要添加不同的图像UITableViewCells以编程方式 我怎样才能做到这一点 我正在尝试一些代码 但图像不显示在UITableViewCells 这是我下面的代码 void viewDidLoad arrImages NSMutab
  • Swift 1.2 和 Swift 2.0 中的字符串长度[重复]

    这个问题在这里已经有答案了 在以前版本的 Swift 中 我有以下代码 func myfunc mystr String if mystr utf16Count gt 3 使用最新版本的 Swift 1 2 我现在收到以下错误 utf16C
  • 如何显示启动图像

    我是 iOS 新手 我的 Xcode 版本是 7 2 1 我尝试使用 Swift 在 iOS9 上运行 我的问题是我对如何创建启动屏幕图像感到非常困惑 我发现有很多方法可以为不同版本的 iOS 创建启动屏幕图像 有人可以向我解释一下如何设置
  • 无法更改 UITabBarItem.image:CSI 中不支持的像素格式

    我试图通过代码更改选项卡栏中显示的图像 我目前正在使用 Swift 和 Xcode 6 beta 3 我导入了 tabBarImage png 并 电子邮件受保护 cdn cgi l email protection在 Images xca
  • 在 Swift 中使用显式对象类型迭代数组

    我有一个数组 let individualScores 75 43 103 87 12 我这样迭代 for score in individualScores 但是 有没有办法显式声明对象类型呢 我认为以后使用自定义对象或其他原因它会派上用
  • Xamarin Form - IOS:如何检测 UIView 大小已更改

    我使用 ContentView 创建了一个 Xamarin 表单 并为 Android 创建了一个渲染器 现在我必须为 IOS 创建一个渲染器 在 android 渲染器中 我可以重写 onSizeChanged 并将这些宽度 高度值传递给
  • 在 wkwebview 中启用摄像头和麦克风访问

    我有一个针对移动设备优化的网络应用程序 它利用getUserMedia访问网络摄像头和麦克风资源 我正在将这个应用程序包装在WKWebView因为我想提供原生应用程序体验 我知道 iOS 不允许通过浏览器访问相机 但是有什么方法可以使用本机
  • 在 Mobile Safari 中点击

    敲击
  • Swift - 带循环的多个链 http 请求

    两天以来 我感觉我正在搜索整个网络来解决多个 http 请求的问题 所以我的工作流程如下所示 将图像上传到服务器 响应 XML 格式和任务 ID 使用任务 ID 向服务器发出 GET 请求 以检查该任务的状态 响应 XML 格式 其中状态可
  • UIPopViewController 不工作

    我有一个 xib 文件 其中有 h 和 m 链接 在 xib 中有一个带有 textView 的 UIView 我想要对该视图执行的操作是 当您单击按钮时将其作为 UIPopViewController 打开 这是我的代码 IBAction
  • 不确定如何在使用故事板时正确子类化 UIApplication

    我想在 X 次用户不活动 没有触发触摸事件 后返回故事板的初始视图控制器 经过一些研究 我发现检测不活动的最常见方法是触发 NSTimer 并在事件触发时重置间隔 为了检测触发的事件 我们在 UIApplication 的子类中重写 UIA

随机推荐

  • 动态创建带有闪亮绘图的选项卡,无需重新创建现有选项卡

    我想创建动态选项卡 每次用户单击按钮时 都会创建一个新选项卡 每个选项卡都具有相同的内容 并具有各种小部件 用户可以使用它们来选择要绘制的数据集 目前 我正在使用该解决方案here https stackoverflow com a 194
  • 如何应用子:悬停但不应用父:悬停

    使用以下 html 当我将鼠标悬停在子级上时 父级上会出现绿色背景 我怎样才能阻止这种情况发生 如果我悬停在子元素之外 我确实想要绿色背景 CSS3 很好 parent padding 100px width 400px height 40
  • 保存在存储库中时,带有 @CreationTimestamp 注释的字段为空

    1 为什么在存储库上调用 CreationTimestamp 字段时 CreationTimestamp 字段值为空 该字段会更新为空 我希望用 CreationTimestamp 注释的字段永远不会在创建时更新和维护一次 但在我当前的项目
  • Nuxt.js - API 调用的最佳场所

    我是 Vue js Nuxt 和所有前端东西的新手 我有一个关于 API 调用的问题 我不确定什么是正确的方法 这里的最佳实践是什么 我有一家商店 在该商店中 我有调用我的 API 并设置状态的操作 例如 async fetchArticl
  • 如何从 android 中的 firebase 检索 List 对象

    我在从 Firebase 检索列表时遇到问题 我存储它没有问题 但是一旦我尝试将 dataSnapshot getValue 转换为 ArrayList 我的应用程序就会崩溃 出现异常 HashMap 无法转换为 ArrayList 但是当
  • Android Studio 1.5.1 上的 AVD Manager 并安装到自定义位置模拟器将无法运行

    I installed Android Studio 1 5 1 see image for build details 安装时我选择了自定义选项 这样我就可以安装特定的路径 我知道我的 SystemDrive 指向一个网络位置 我想安装到
  • 禁用 Chrome 66 中的自动完成功能

    有没有办法禁用 chrome 66 中文本字段的自动完成功能 我尝试过多种选择 例如 自动完成 关闭 自动完成 假 自动完成 已禁用 自动完成 新东西 ETC 谁能帮我这个 另外 如果用户名下面有密码类型字段 chrome 还会自动启用用户
  • 在 JS 中初始化空变量的最佳方法是什么?

    如果我知道该变量稍后将是对象 我使用 var obj 但如果我将其初始化为 null 或 undefined 并不重要 var obj null or var obj undefined 对于我个人使用的字符串 var str 稍后我可以做
  • std::chrono::duration::duration() 如何成为 constexpr?

    默认构造函数std chrono duration定义如下 constexpr duration default 例如 参见cppreference com http en cppreference com w cpp chrono dur
  • 视图和超级视图自动布局的比例高度

    我有一个小视图 我希望他占据超级视图的 1 3 高度 与安全区域大小相同 我用 superview bottom 定义了前导空间 尾随空间 底部空间 其常数 0 AND I want to make the height 1 3 of su
  • 将 ActorRef 传递给其他 Actor 是好是坏?

    我想弄清楚我是否使用传递 AkkaActorRef围绕其他参与者并不是一种反模式 我的系统中有一些演员 有些寿命很长 restClientRouter publisher 有些人在完成工作后就死了 geoActor 短命参与者需要向长命参与
  • 如何从.key和.crt文件获取.pem文件?

    如何从 SSL 证书创建 PEM 文件 这些是我可用的文件 crt server csr server key 您的密钥可能已经是 PEM 格式 但只是以 crt 或 key 命名 如果文件的内容开头为 BEGIN您可以在文本编辑器中阅读它
  • 如何使用 GluonHQ 客户端、Native Image 和 GraalVM 解决已编译的 JavaFX 项目中的 fxml 加载异常?

    这是一个后续问题this https stackoverflow com questions 63419433 how to use graalvm with javafx to compile a native image in mave
  • Angular 2 backgrounImage 中的样式绑定抛出错误

    我正在尝试使用 Angular 2 创建一个应用程序 这是我的模板 div class cover user profile div 我认为 angular2 认为 url 是一个函数并抛出错误 这个问题的解决方案是什么 符号期望expre
  • 如何防止图表中的刻度标签被切断?

    我有问题chartjs http chartjs org其中刻度标签通过以下方式被 切断 1 是否有可以设置的边距 我在 ChartJS 文档中没有看到任何关于此的内容 并且这些似乎包含在 ChartJS Canvas 元素中 意思是 不被
  • 表格视图图像从未发布

    我正在对我的一个应用程序进行重大更新 并尝试减少内存使用量并使其更干净 更快 我正在使用 Instruments 来分析应用程序 并且正在查看 UIImage 分配 当应用程序启动时 我有大约 10 个 尽管其中一个是状态栏图标 不知道为什
  • 不断刷新jquery数据

    我有这个代码 它正在计算某个项目被选择的次数 但是 只有当我在更改选项后刷新页面时 它才可以正常工作和计数 我需要一种方法让它不断刷新或 实时 所以如果它每秒自动刷新 每次页面中发生更改时它都会正确反映 我知道如何进行整页自动刷新 但我不想
  • 将 cookie 传递给 GET 请求(POST 之后)的问题

    我在这个问题上被困了好几天了 由于尝试不同的组合但没有成功 我的眼睛开始受伤 问题是 我正在制作一个应用程序 它必须从互联网获取数据 解析它 然后将其显示给用户 我已经尝试了多种方法来做到这一点 并且使用 JSOUP 非常有帮助 尤其是在解
  • 它是什么以及如何摆脱它

    我注意到 在查看我的页面源代码时 这些字符 shy 紧接着显示 div 标签 我检查了我的编码 但找不到它来自哪里 我做了一些研究 他们说它就在那里 所以可以省去一些话 靠近 h1 标签 我有一个比标题大一点的浮动图像 我想知道这是否是造成
  • SwiftUI:从单元格视图中删除托管对象会使应用程序崩溃[非可选属性]?

    我发布了这个问题 SwiftUI 从单元格视图中删除托管对象会使应用程序崩溃 https stackoverflow com questions 73159270 swiftui deleting managed object from c