[英]How can I use Key-Value Observing with Smart KeyPaths in Swift 4?
您能否帮助我在使用Smart KeyPaths修改NSArrayController
的内容时如何设置通知?
灵感来自
键值观察 : https : //developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID12
Smart 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
的Mode是实体名称 ,用Document.xcdatamodeld
编写
myArrayController
的托管对象上下文绑定到模型密钥路径 : representedObject.managedObjectContext
representedObject
被赋予Document
实例。 NSTableView
的内容 , 选择索引和排序描述符绑定到myArrayController
的对应myArrayController
。 有关环境的更多信息: 绑定managedObjectContext,Xcode 8.3.2,Storyboards,mac : https : //forums.bignerdranch.com/t/binding-managedobjectcontext-xcode-8-3-2-storyboards-macos-swift/12284
编辑 :
关于上面引用的示例案例,我已经改变主意去观察managedObjectContext
,而不是NSArrayController
的content
。
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)")
}
}
原因是第二种方法比第一种方法简单。 此代码涵盖了所有所需的要求:表行的添加和删除,以及表单元格值的修改。 缺点是每个其他表的修改和应用程序中的每个其他实体的修改都将导致通知。 但是,这样的通知并不有趣。 但是,这不是什么大问题。
相反,第一种方法需要更多的复杂性。
对于添加和删除,我们需要观察NSArrayController
content
或实现两个函数
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()
函数都会被频繁调用。 例如,在表中有十行的情况下,排序行将导致十个didRemove
调用,然后是十个didAdd
调用; 添加一行将导致十个didRemove
调用,然后十一个didAdd
调用。 那不是那么有效。
对于修改,我们需要
func control(_ control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool
来自NSControlTextEditingDelegate
,一个超级的NSTableViewDelegate
。 每个表列的每个NSTextField
NSViewController
通过其delegate
连接到NSViewController
。
此外,遗憾的是,在文本编辑完成后立即调用此control()
,而是在NSArrayController
的实际值更新之前NSArrayController
。 那是有点无用的。 我还没有找到第一种方法的好解决方案。
无论如何 ,这篇文章的主要内容是如何使用Smart KeyPaths 。 :-)
编辑2 :
我要两个都用
NSArrayController
的属性content
......第一个 NSManagedObjectContext
发布的Notification
......第二个 1表示用户更改主 - 详细信息视图时,该视图不会对NSManagedObjectContext
进行更改。
2用于当用户对其进行更改时:添加,删除,更新以及撤消Command-Z ,其中没有鼠标事件。
现在,将使用addObserver(self, forKeyPath: "content", ...
的版本addObserver(self, forKeyPath: "content", ...
。一旦这篇文章的问题得到解决,我将切换到observe(\\.content, ...
的版本observe(\\.content, ...
addObserver(self, forKeyPath: "content", ...
observe(\\.content, ...
谢谢。
编辑3 :
代码2.观察Notification
已完全被新的替换。
至于你的初始代码,这里应该是这样的:
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
,您将不再收到通知。 在您的情况下,您从未保留对象,因此它在方法范围之后立即死亡。
另外,要手动停止观察,只需将mySub
设置为nil
,这会隐式deinit
旧的观察者对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.