0

我正在尝试创建一个基本的基于文​​档的 SwiftUI 应用程序。但是,Xcode 创建的骨架在文档和内容视图之间没有任何联系。这是我推断的正确方法:

struct Task {
  var done: Bool
  var text: String
}

class Document: NSDocument {
  var task: Task = Task(done: false, text: "") // Declaration A: task content
  override class var autosavesInPlace: Bool { true }
  override func makeWindowControllers() {
    let contentView = ContentView(document: self)
    let window = NSWindow(
      contentRect: NSRect(x: 0, y: 0, width: 250, height: 300),
      styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
      backing: .buffered, defer: false)
    window.center()
    window.contentView = NSHostingView(rootView: contentView)
    let windowController = NSWindowController(window: window)
    self.addWindowController(windowController)
  }
}

struct ContentView: View {
  @State var document: Document // Declaration B: link to document
  var body: some View {
    HStack {
      Toggle(isOn: $document.task.done) { EmptyView() }
      TextField("Description", text: $document.task.text)
    }.padding()
  }
}

(这是我的全部代码,除了 Xcode 生成的骨架)

但是,在生成的应用程序中,编辑似乎没有任何效果。该复选框不可选中,并且对文本字段的编辑将被还原。

如果不是上面的声明 A 和 B,那么声明文档内容的正确方法是什么,以及文档和内容视图之间的链接?

4

1 回答 1

0

这是我迄今为止最好的:

class Document: NSDocument, ObservableObject {
  @Published var task: Task = Task(done: false, text: "") {
    willSet {
      let copy = task
      undoManager?.registerUndo(withTarget: self) { $0.task = copy }
    }
  }

  // makeWindowControllers() unchanged from above
}

struct ContentView: View {
  @ObservedObject var document: Document
  var body: some View {
    HStack {
      Toggle(isOn: $document.task.done) { EmptyView() }
      TextField("Description", text: $document.task.text)
    }.padding()
  }
}

撤消现在有效,但在文本字段的情况下,它一次只对一个字符进行操作。我不知道如何支持正常的文本字段撤消,同时还允许文档级撤消。我认为文本字段应该有自己的、单独的 undoManager,但我在 SwiftUI 中看不到它的钩子。

于 2020-06-14T00:49:54.107 回答