ios - NSManagedObject 的 objectID 保存到变量中,但是从 .sheet 处理程序调用时该变量已变为 nil
问题描述
我正在构建的 iOS 应用程序遍历 Core Data 中定义的 PhraseGroup 对象列表,并显示extraText
与每个 PhraseGroup 关联的值。
这是 Xcode 为 PhraseGroup 生成的 NSManagedObject 子类的顶部:
extension PhraseGroup {
@nonobjc public class func fetchRequest() -> NSFetchRequest<PhraseGroup> {
return NSFetchRequest<PhraseGroup>(entityName: "PhraseGroup")
}
@NSManaged public var extraText: String?
@NSManaged public var phraseGroupID: UUID
@NSManaged public var text: String?
@NSManaged public var phrase: NSSet?
@NSManaged public var piece: Piece
我希望用户能够长按显示列表中的任何 extraText 条目,然后在模式表中对其进行编辑。但是,我正在努力寻找一种方法,将对长按 PhraseGroup 的有效引用传递给我的工作表。
下面显示了我如何显示 PhraseGroupsextraText
值的列表:
import SwiftUI
import CoreData
struct PhraseGroupView: View {
@Environment(\.managedObjectContext) var moc
@Binding var phraseGroupViewAlertItem: AlertItem?
@State private var isEditMode: EditMode = .inactive
@State private var showingPhraseGroupEditView = false
@State private var phraseGroupObjectID: NSManagedObjectID!
private var fetchRequest: FetchRequest<PhraseGroup>
private var phraseGroups: FetchedResults<PhraseGroup> { fetchRequest.wrappedValue }
var body: some View {
NavigationView {
VStack(spacing: 20){
Section {
List {
ForEach (phraseGroups, id: (\PhraseGroup.phraseGroupID)) { phraseGroup in
HStack {
Text("\(phraseGroup.wrappedExtraText)")
}
.onLongPressGesture {
phraseGroupObjectID = phraseGroup.objectID
showingPhraseGroupEditView = true
print(phraseGroup.extraText!) // Sanity check to prove I've got hold of the right row
let phraseGroupForEditing = moc.object(with: phraseGroupObjectID) as! PhraseGroup
dump(phraseGroupForEditing)
print(phraseGroupForEditing.extraText!)
}
}
.onDelete(perform: delete)
}
.sheet(isPresented: $showingPhraseGroupEditView) {
self.phraseGroupObjectID == nil
?
TestPhraseGroupEditView(phraseGroupObjectID: phraseGroupObjectID, message: "phraseGroupObjectID is nil")
:
TestPhraseGroupEditView(phraseGroupObjectID: phraseGroupObjectID, message: "phraseGroupObjectID is not nil")
}
}
}
.navigationBarTitle("This is phraseGroup navBarTitle", displayMode: .inline)
.navigationBarItems(leading:
HStack {
Button(action: {
// yet to come
}) {
Image(systemName: "plus").resizable()
.frame(width: 16, height: 16)
.aspectRatio(contentMode: .fit)
.foregroundColor(.myKeyColor)
}
}, trailing:
HStack {
EditButton()
.frame(width: 60, height: 20)
.aspectRatio(contentMode: .fit)
.foregroundColor(.myKeyColor)
})
.environment(\.editMode, self.$isEditMode)
}
}
我正在使用以下初始化函数来设置此视图:
init (phraseGroupViewAlertItem: Binding<AlertItem?>, piece: Piece) {
self._phraseGroupViewAlertItem = phraseGroupViewAlertItem
fetchRequest = FetchRequest<PhraseGroup>(
entity: PhraseGroup.entity(),
sortDescriptors: [
NSSortDescriptor(key: "extraText", ascending: true)
],
predicate: NSPredicate(format: "piece == %@", piece)
// 'piece' in the predicate above is the name of a Piece <- PhraseGroup relationship defined in Core Data
)
}
当我长按列表中的一行时,我可以在调试器中看到,逐步通过onLongPressGesture
闭包,我已经掌握了正确的 PhraseGroup(即我按下的那个),我正在正确阅读将 PhraseGroupobjectID
放入 @State var,然后创建对同一核心数据对象的另一个引用并输出其extraText
值。
但是,当 .sheet 关闭之后立即出现时,phraseGroupObjectID 已设置为零,当显示 TestPhraseGroupEditView 时我可以清楚地看到。
import SwiftUI
import CoreData
struct TestPhraseGroupEditView: View {
@Environment(\.managedObjectContext) var moc
var phraseGroupObjectID: NSManagedObjectID!
var message: String
var body: some View {
VStack (spacing: 20){
Text(message)
Text("Tap to create phraseGroup for debugger").onTapGesture {
dump(phraseGroupObjectID)
let phraseGroupForEditing = moc.object(with: phraseGroupObjectID) as! PhraseGroup
dump(phraseGroupForEditing)
}
}
}
}
第一个 Text 字段中的消息为phraseGroupObjectID is nil
,单击第二个 Text 会导致第一个 dump() 打印-nil
,然后是Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file AK6/TestPhraseGroupEditView.swift, line 22
我在这里无法理解的是什么?我忽略了我的实现中是否存在一些小故障,或者我是否以完全错误的方式解决这个问题?Apple 在https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/FaultingandUniquing.html上有一些关于故障或唯一性的非常好的文档,但我在那里读到的任何内容都没有让我感到震惊一个明显的解决我的问题的方法。
解决方案
您可以使用可选对象并将数据直接传递到工作表中,而不是使用 Bool 来切换工作表。将您的 phaseGroupObjectID 定义更改为以下内容
@State private var phraseGroupObjectID: NSManagedObjectID? = nil
将您的 .onLongPressGesture 更改为以下内容
.onLongPressGesture {
phraseGroupObjectID = phraseGroup.objectID
print(phraseGroup.extraText!) // Sanity check to prove I've got hold of the right row
let phraseGroupForEditing = moc.object(with: phraseGroupObjectID) as! PhraseGroup
dump(phraseGroupForEditing)
print(phraseGroupForEditing.extraText!)
}
将您的工作表更改为以下内容
.sheet(item: $self.phraseGroupObjectID) { objID in
TestPhraseGroupEditView(phraseGroupObjectID: objID, message: "phraseGroupObjectID is not nil")
}
您现在可以删除显示PhraseGroupEditView。
只要 phaseGroupObjectID 不为零,就会显示工作表。您可以通过将 phaseGroupObjectID 再次设置为 nil 来关闭工作表。
推荐阅读
- tabulator - 更新另一个单元格的制表符自动完成功能
- javascript - React - 如何向数组添加新值并在警报窗口中显示该数组?
- c# - 无法加载文件或程序集“系统
- javascript - 在javascript中提取和更改base64图像数据
- knex.js - 查询更多 1000 条记录时,Knex 0.95.4 无法使用 oracle 11g 引发异常 ORA 01795
- azure-iot-edge - 通过一个 Azure 管道和一个版本将两个 IoT Edge 模块发布到暂存和生产环境中的一个 IoT Edge 设备
- opencart2.x - 只能通过 /admin login OPENCART 2.3.0.2 访问 FTP
- spring - 如何在 Spring Boot 上初始化 Jackson 以获取快速的第一个请求?
- python-3.x - 如何在熊猫数据框中添加一个复选框
- ruby-on-rails - 如何在 Rails 控制台中根据列格式过滤模型