我使用两个CoreData
实体,两个NSTableView
和两个NSArrayController
创建了一个简单的主详细信息应用程序,通过绑定而不是编写代码来连接所有内容。我想记住并恢复每个主行的选定详细信息行。
主实体有标题和多个细节(一对多关系):
class Master: NSManagedObject {
}
// Generated
extension Master {
@NSManaged var title: String?
@NSManaged var details: NSSet?
}
详情实体只有一个标题:
class Detail: NSManagedObject {
}
// Generated
extension Master {
@NSManaged var title: String?
}
第一个表视图显示所有主实体,第二个表视图显示第一个表中所选主实体的所有详细信息实体。两个表视图都配置为仅允许单个选择:
我现在想要做的是在主实体中存储所选细节的索引。当再次选择相同的主实体时,第二个表视图应自动恢复该选择并再次选择相同的细节。
为了方便起见,我在selectionIndexes: NSIndexSet
实体中添加了一个简单的Master
属性。然后我将此属性绑定到NSArrayController的选择索引属性的详细信息:
拥有此选择索引绑定实际上存储了所选的详细信息索引,但是当再次选择相同的主实体时,某些Cocoa代码会将选择重置为空。这表示存储的选择被空选择覆盖。
Avoid Empty Selection
和Preserve Selection
是禁用的,以避免NSArrayController在没有选择项目的情况下自动选择项目,或者在内容发生变化时始终尝试再次选择相同项目(这不是我想要的因为不同主实体可能具有相同标题的详细信息。)
我已查看get
和set
对selectionIndexes
媒体资源的调用,例如:
class Master: NSManagedObject {
var _selection = NSMutableIndexSet()
var selectionIndexes: NSIndexSet {
get {
print("get", _selection)
return _selection
}
set(selection) {
_selection.removeAllIndexes()
_selection.addIndexes(selection)
print("set", _selection)
//print(NSThread.callStackSymbols())
}
}
}
这是通话记录:
选择第一个主实体的第三个细节:
set [number of indexes: 1 (in 1 ranges), indexes: (2)] get [number of indexes: 1 (in 1 ranges), indexes: (2)]
选择其他主要实体:
get (no indexes)
然后再次选择第一个主实体:
get [number of indexes: 1 (in 1 ranges), indexes: (2)] set (no indexes) get (no indexes)
如您所见,它首先恢复索引2
(第3个详细信息实体),然后分配(no indexes)
。为什么此时会重新分配selectionIndexes
?这是最后一次set
调用的调用堆栈:
"0 SelectionTest 0x00000001000029fd _TFC13SelectionTest6Masters16selectionIndexesCSo10NSIndexSet + 797", "1 SelectionTest 0x00000001000026ca _TToFC13SelectionTest6Masters16selectionIndexesCSo10NSIndexSet + 58", "2 Foundation 0x00007fff9d2a6c13 _NSSetObjectValueAndNotify + 148", "3 AppKit 0x00007fff9c9f09ae -[NSArrayController _setMultipleValue:forKeyPath:atIndex:] + 208", "4 Foundation 0x00007fff9d25d80f -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] + 287", "5 AppKit 0x00007fff9c88a72e -[NSBinder _setValue:forKeyPath:ofObject:mode:validateImmediately:raisesForNotApplicableKeys:error:] + 411", "6 AppKit 0x00007fff9c88a53c -[NSBinder setValue:forBinding:error:] + 248", "7 AppKit 0x00007fff9ca958c3 -[NSControllerConfigurationBinder _updateSelectionIndexes:] + 226", "8 AppKit 0x00007fff9ca95ab0 -[NSControllerConfigurationBinder _observeValueForKeyPath:ofObject:context:] + 111", "9 Foundation 0x00007fff9d255a53 NSKeyValueNotifyObserver + 379", "10 Foundation 0x00007fff9d25fd7a -[NSObject(NSKeyValueObservingPrivate) _notifyObserversForKeyPath:change:] + 1127", "11 AppKit 0x00007fff9c6e57d8 -[NSController _notifyObserversForKeyPath:change:] + 206", "12 AppKit 0x00007fff9c74242b -[NSArrayController didChangeValuesForArrangedKeys:objectKeys:indexKeys:] + 126", "13 AppKit 0x00007fff9c74208f -[NSArrayController _selectObjectsAtIndexesNoCopy:avoidsEmptySelection:sendObserverNotifications:forceUpdate:] + 584", "14 Foundation 0x00007fff9d23c178 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 424", "15 AppKit 0x00007fff9c88a72e -[NSBinder _setValue:forKeyPath:ofObject:mode:validateImmediately:raisesForNotApplicableKeys:error:] + 411", "16 AppKit 0x00007fff9c88a53c -[NSBinder setValue:forBinding:error:] + 248", "17 AppKit 0x00007fff9c868931 -[NSTableBinder tableView:didChangeToSelectedRowIndexes:] + 138", "18 AppKit 0x00007fff9c868857 -[_NSBindingAdaptor tableView:didChangeToSelectedRowIndexes:] + 153", "19 AppKit 0x00007fff9c728504 -[NSTableView _sendSelectionChangedNotificationForRows:columns:] + 119", "20 AppKit 0x00007fff9c6f9723 -[NSTableView _enableSelectionPostingAndPost] + 424", "21 AppKit 0x00007fff9c881a15 -[NSTableView mouseDown:] + 5358", "22 AppKit 0x00007fff9cd83d1d -[NSWindow _handleMouseDownEvent:isDelayedEvent:] + 6322", "23 AppKit 0x00007fff9cd84fad -[NSWindow _reallySendEvent:isDelayedEvent:] + 212", "24 AppKit 0x00007fff9c6dd735 -[NSWindow sendEvent:] + 517", "25 AppKit 0x00007fff9c6d9e49 -[NSApplication sendEvent:] + 2540", "26 AppKit 0x00007fff9c60d03a -[NSApplication run] + 796", "27 AppKit 0x00007fff9c58f520 NSApplicationMain + 1176", "28 SelectionTest 0x0000000100004d07 main + 87", "29 libdyld.dylib 0x00007fff892705ad start + 1", "30 ??? 0x0000000000000003 0x0 + 3"
现在显而易见的问题是:如何让NSArrayController存储并将选定的详细信息索引恢复到其主实体中,而不会让其他人覆盖它?