Could you help me find out how to get notified when the contents of NSArrayController are changed using Smart KeyPaths ?
Inspired
Monitoring Key Values : https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID12
Smart KeyPaths: best key coding for Swift : https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md
I imitated the example code of an article.
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)") } } }
However, this does not work. Any changes made to the target do not cause a notification.
In contrast, the typical method below works.
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) } } }
The new way looks more elegant. Any of your suggestions?
Wednesday: Xcode 9 Beta p>
Additional environmental information: managedObjectContext binding, Xcode 8.3.2, storyboards, mac : https://forums.bignerdranch.com/t/binding-managedobjectcontext-xcode-8-3-2-storyboards-macos-swift/12284
EDITED
As for the example above, I changed my mind to observe managedObjectContext instead of content 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)") } }
The reason is that this second approach is simpler than the first. This code covers all the required requirements: adding and deleting table rows and changing table cell values. The disadvantage is that every other table modification and every other modification in the application will cause notifications. However, such a notice is not interesting. However, this is not a big problem.
On the contrary, the first approach will require more complexity.
For additions and exceptions, we need to either observe the content of NSArrayController , or implement two functions
func tableView(_ tableView: NSTableView, didAdd rowView: NSTableRowView, forRow row: Int) func tableView(_ tableView: NSTableView, didRemove rowView: NSTableRowView, forRow row: Int)
from NSTableViewDelegate . NSTableView delegate connected to the NSViewController .
Surprisingly, both tableView() functions will be called so often. For example, in a situation where there are ten rows in a table, sorting the rows will result in ten didRemove calls followed by ten didAdd calls; adding one line will result in ten didRemove calls, and then eleven didAdd calls. It is not so effective.
For modifications we need
func control(_ control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool
from NSControlTextEditingDelegate , super NSTableViewDelegate . Each NSTextField each table column must be connected to the NSViewController through its delegate .
In addition, unfortunately, this control() is called immediately after the completion of the text edition, but rather before the actual value is NSArrayController in NSArrayController . That is, somewhat, it is useless. I did not find a good solution with the first approach.
ANYWAY , the main topic in this post is the use of Smart KeyPaths . :-)
EDITED 2 :
I'm going to use both
- respecting the
content of NSArrayController ... first - watching the
Notification posted by NSManagedObjectContext ... second
The value 1 is when the user changes the appearance of the master data, which does not make the change to NSManagedObjectContext .
2 - this is when the user makes changes: add, delete, update, and also cancel, Command-Z , which is not accompanied by mouse events.
The addObserver(self, forKeyPath: "content", ... version addObserver(self, forKeyPath: "content", ... will be used now. Once the issue of this message has been resolved, I will switch to the observe(\.content, ... version observe(\.content, ...
Thanks.
EDITED 3 :
Code 2. Observation a Notification been completely replaced by a new one.