让 SwiftUI Toggle 控制 Core Data 对象的 Bool 会导致崩溃

Having a SwiftUI Toggle control a Bool of a Core Data object causes a crash

我有一个名为 Note 的模型,它是由 Core Data 自动生成的 NSManagedObject。它有一个 pinned 属性 是一个非可选的 Bool。我正在尝试将 Bool 传递到 Toggle 视图中,但这会导致崩溃:

2019-09-09 12:38:11.647030-0500 MyApp[12336:2688627] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Note pinned]: unrecognized selector sent to instance 0x2837e42d0'
*** First throw call stack:
(0x1a665897c 0x1a63810a4 0x1a655c42c 0x1a665cdf8 0x1a665ebdc 0x104f83cd4 0x1b37f0900 0x1b37f0528 0x1b37f02b8 0x1b37f2278 0x1dbcd19f0 0x1dc2aa43c 0x1dc2ab504 0x104f83bf4 0x1dbf41f30 0x1dbf42a64 0x104f83680 0x1dc2c4f98 0x104f826c4 0x1dbd8b484 0x104f82450 0x104f85124 0x1dbd158e4 0x1dbd16070 0x1d0600458 0x1d05e8a60 0x1d05e8d24 0x1d05eda0c 0x1dbe41838 0x1dbe41b64 0x1dbe418ec 0x1dc1a82bc 0x1dc1a7d24 0x1dc19e600 0x1dc32122c 0x1dc321258 0x1aaaed5e8 0x1acfd6460 0x1acfdac90 0x1aaad989c 0x1a9f891c4 0x1a9f86b7c 0x1a9f8b0cc 0x1aaae0080 0x1a9f8b000 0x1aa0817b0 0x1aa07e160 0x1aaadfe50 0x1aaab4e18 0x1aaab3cc4 0x1aaab1408 0x1aaae179c 0x1aaae1d28 0x1aaaacc88 0x1aaae22ec 0x1aaaac8a8 0x1aaaac344 0x1aa07a790 0x1aa0823d0 0x1aa18ea58 0x1aa082360 0x1aaadfd38 0x1aa0821c8 0x1a9f7a648 0x1aa66c3c4 0x1aa65bfec 0x1aa68bdc0 0x1a65d5c38 0x1a65d0b24 0x1a65d10f0 0x1a65d08ac 0x1b042b328 0x1aa662f00 0x104f716d0 0x1a645b460)
libc++abi.dylib: terminating with uncaught exception of type NSException

我的包含 Toggle 的视图:

struct NoteInfo: View {

  @Binding var note: Note

  var body: some View {
    NavigationView {
      Form {
        Section {
          Toggle(isOn: $note.pinned) {
            Text("Pinned")
          }
        }
      }
    }
  }

}

自动生成的备注代码:

@objc(Note)
public class Note: NSManagedObject {

}

extension Note {

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

    @NSManaged public var modifiedAt: Date?
    @NSManaged public var pinned: Bool
    @NSManaged public var trashed: Bool
    @NSManaged public var unsecuredContent: String?

}

不好意思,我的 Core Data 模型的 pinned 字段以某种方式被删除了,但是生成的代码与它不同步,所以这不是 SwiftUI 的问题。

这对我有用:

import SwiftUI

struct TaskRow: View {

    var task: Task

    // States of the Task
    @Binding var isCompleted: Bool

    var body: some View {
        HStack {
            // Toggle
            Toggle(isOn: $isCompleted) {
                EmptyView()
            }
            // And so on...
        }
    }
}
import CoreData
import SwiftUI

struct TableView: View {

    @EnvironmentObject var model: TasksViewModel

    var body: some View {
        List {
            ForEach(model.items) { task in
                TaskRow(task: task,
                isCompleted: model.toggleCompletion(of: task))
            }
        }
    }
}
import Combine
import CoreData
import SwiftUI

class TasksViewModel: NSObject, ObservableObject {

    func toggleCompletion(of task: Task) -> Binding<Bool> {

        let binding = Binding<Bool>(get: { () -> Bool in
            return task.completedAt != nil

        }) { (newValue) in
            // This func updates the database
            toggleCompletion(of: task, isCompleted: newValue)
        }
        return binding
    }
}

Medium 上的文章 - https://medium.com/@voevodin/swiftui-list-with-toggle-coredata-5eb6f52a390a