当NSArrayController的内容被修改时,您能帮助我如何使用智能KeyPaths获得通知吗?
灵感来自
键值观察:ref/doc/uid/TP40014216-CH7-ID12
智能KeyPaths: Swift:https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md的更好的键值编码
我模仿了本文的示例代码。
class myArrayController: NSArrayController {
required init?(coder: NSCoder) {
super.init(coder: coder)
observe(\.content, options: [.new]) { object, change in
print("Observed a change to \(object.content.debugDescription)")
}
}
}然而,这是行不通的。对目标对象所做的任何更改都不会触发通知。
相反,下面列出的典型方式是工作。
class myArrayController: NSArrayController {
required init?(coder: NSCoder) {
super.init(coder: coder)
addObserver(self, forKeyPath: "content", options: .new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "content" {
print("Observed a change to \((object as! myArrayController).content.debugDescription)")
}
else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
}新的方式看起来更优雅。你有什么建议吗?
环境: Xcode 9 Beta
myArrayController的模式是实体名,由Document.xcdatamodeld编写。myArrayController的托管对象上下文绑定到模型密钥路径:representedObject.managedObjectContextrepresentedObject与Document实例一起分配。NSTableView的Content、选择索引和排序描述符绑定到myArrayController的对应项。有关环境的更多信息:绑定managedObjectContext,Xcode 8.3.2,故事板,mac:https://forums.bignerdranch.com/t/binding-managedobjectcontext-xcode-8-3-2-storyboards-macos-swift/12284
编辑的
关于上面引用的例子,我改变了主意,以观察managedObjectContext,而不是content of NSArrayController。
class myViewController: NSViewController {
override func viewWillAppear() {
super.viewWillAppear()
let n = NotificationCenter.default
n.addObserver(self, selector: #selector(mocDidChange(notification:)),
name: NSNotification.Name.NSManagedObjectContextObjectsDidChange,
object: (representedObject as! Document).managedObjectContext)
}
}
@objc func mocDidChange(notification n: Notification) {
print("\nmocDidChange():\n\(n)")
}
}原因是第二种方法比第一种更简单。此代码涵盖所有所需的要求:表行的添加和删除,以及表单元格值的修改。缺点是,应用程序中的每一个表的修改和另一个实体的修改都会导致通知。然而,这样的通知并不有趣。然而,这并不是什么大事。
相反,第一种方法将需要更多的复杂性。
对于添加和删除,我们需要观察content of NSArrayController或实现两个函数
func tableView(_ tableView: NSTableView, didAdd rowView: NSTableRowView, forRow row: Int)
func tableView(_ tableView: NSTableView, didRemove rowView: NSTableRowView, forRow row: Int)来自NSTableViewDelegate。NSTableView的delegate与NSViewController相连。
稍微令人惊讶的是,这两个tableView()函数都会被频繁调用。例如,在表中有10行的情况下,排序行将导致10个didRemove调用,然后是10个didAdd调用;添加一行将导致10个didRemove调用,然后是11个didAdd调用。这不是很有效率。
对于修改,我们需要
func control(_ control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool来自NSControlTextEditingDelegate,NSTableViewDelegate的超级品牌。每个表列的每个NSTextField都应该通过其NSViewController的delegate连接到NSViewController。
此外,不幸的是,这个control()是在文本版本完成之后调用的,而是在NSArrayController中的实际值更新之前调用的。这在某种程度上是无用的。我还没有找到第一种办法的好解决办法。
无论如何,,这篇文章的主要主题是如何使用智能KeyPaths。:-)
编辑2
我要用这两种
content of NSArrayController .第一个Notification被NSManagedObjectContext .第二个1用于当用户更改主细节视图时,该视图不会在NSManagedObjectContext上进行更改。
2用于当用户对其进行更改时:添加、删除、更新以及撤销、命令-Z,它不伴随鼠标事件。
目前,将使用addObserver(self, forKeyPath: "content", ...的版本。一旦这个帖子的问题解决了,我将切换到observe(\.content, ...的版本。
谢谢。
编辑3
观察Notification的代码2已经完全被新的代码所取代。
发布于 2017-07-14 08:19:30
至于您的初始代码,如下所示:
class myArrayController: NSArrayController {
private var mySub: Any? = nil
required init?(coder: NSCoder) {
super.init(coder: coder)
self.mySub = self.observe(\.content, options: [.new]) { object, change in
debugPrint("Observed a change to", object.content)
}
}
}observe(...)函数返回一个临时观察者,该观察者的生存期指示您将接收通知的时间。如果返回的观察者是deinit'd,您将不再接收通知。在您的示例中,您从未保留该对象,因此它在方法作用域之后立即死亡。
此外,要手动停止观察,只需将mySub设置为nil,这意味着deinit是旧的观察者对象。
https://stackoverflow.com/questions/44827613
复制相似问题