我正在尝试使用“自动保存扩展项目”功能。当我使用其子项扩展组并重新启动应用程序时,所有子项都会再次崩溃,我不知道为什么它们不会保持扩展状态。 我正在使用核心数据来存储我的源列表项。
这就是我到目前为止所做的事情:
这是我对outlineView的实现:persistentObjectForItem和outlineView:itemForPersistentObject。
- (id)outlineView:(NSOutlineView *)anOutlineView itemForPersistentObject:(id)object
{
NSURL *objectURI = [[NSURL alloc] initWithString:(NSString *)object];
NSManagedObjectID *mObjectID = [_persistentStoreCoordinator managedObjectIDForURIRepresentation:objectURI];
NSManagedObject *item = [_managedObjectContext existingObjectWithID:mObjectID error:nil];
return item;
}
- (id)outlineView:(NSOutlineView *)anOutlineView persistentObjectForItem:(id)item
{
NSManagedObject *object = [item representedObject];
NSManagedObjectID *objectID = [object objectID];
return [[objectID URIRepresentation] absoluteString];
}
有什么想法吗?感谢。
修改 我有一个线索!问题可能是树控制器没有按时准备其内容。方法applicationDidFinishLaunching,outlineView:persistentObjectForItem等在数据加载之前执行,或者NSOutlineView尚未完成初始化。任何想法如何解决这个问题?
答案 0 :(得分:3)
我遇到的问题是我的-outlineView:itemForPersistentObject:的实现根本没有被调用。事实证明,当设置“autosaveExpandedItems”或“autosaveName”时,将调用此方法。 我的解决方案是在CodeBuilder中设置Code中的两个属性。当我在分配委托后设置属性时,将调用该方法。
答案 1 :(得分:1)
我让这个工作 - 你需要返回相应的树节点,而不是“只”它表示的对象。
在itemForPersistentObject:
,而不是return item;
,您需要return [self itemForObject:item inNodes:[_treeController.arrangedObjects childNodes]];
与
- (id)itemForObject:(id)object inNodes:(NSArray *)nodes {
for (NSTreeNode *node in nodes) {
if ([node representedObject] == object)
return node;
id item = [self itemForObject:object inNodes:node.childNodes];
if (item)
return item;
}
return nil;
}
其中_treeController
是用于填充大纲视图的NSTreeController
实例。
答案 2 :(得分:1)
扩展Karsten的解决方案:
在执行Karsten建议之后调用方法-outlineView:itemForPersistentObject:
,但只有在设置委托之前还设置数据源时才会调用。
因此,如果Karsten的答案似乎不起作用,请检查数据源的设置位置并进行相应调整。
(想把它写成评论,但由于我的新手状态,我不被允许......)
答案 3 :(得分:0)
我从来没有这样做过。
这是我目前的做法:
首先,我添加了一个属性" isExpanded"并为每个节点保存数据库中的状态。
其次,我在treeController准备好内容时展开节点。
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[treeSectionController addObserver:self
forKeyPath:@"content"
options:0
context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == treeSectionController) {
NSArray *sectionArray = [[treeSectionController arrangedObjects] childNodes];
for (NSTreeNode *node in sectionArray) {
if([[node representedObject] isExpandedValue]) {
[outlinePilesView expandItem:node];
}
}
[treeSectionController removeObserver:self forKeyPath:@"content"];
}
}
答案 4 :(得分:0)
快速5个答案
Karsten是正确的,itemForPersistentObject
必须返回一个NSTreeNode。
这是该解决方案的Swift 5版本:
// This method should return a NSTreeNode object
func outlineView(_ outlineView: NSOutlineView, itemForPersistentObject object: Any) -> Any? {
guard let uriAsString = object as? String,
let uri = URL(string: uriAsString) else { return nil }
if let psc = self.managedObjectContext.persistentStoreCoordinator,
let moID = psc.managedObjectID(forURIRepresentation: uri),
let group = self.managedObjectContext.object(with: moID) as? MyGroupEntity,
let nodes = self.expensesTreeController.arrangedObjects.children {
return self.findNode(for: group, in: nodes)
}
return nil
}
/// Utility method to find the corresponding NSTreeNode for a given represented object
private func findNode(for object: NSManagedObject, in nodes: [NSTreeNode]) -> NSTreeNode? {
for treeNode in nodes {
if (treeNode.representedObject as? NSManagedObject) === object {
return treeNode
}
}
return nil
}
答案 5 :(得分:0)
哇! 6 年过去了,这仍然令人头疼。
即使使用 Karsten 有用的解决方案在代码中重新设置 autoSaveName 和 autosaveExpandedItems,我最初也无法使其正常工作; itemForPersistentObject 在填充大纲视图之前仍然被调用。对我来说,虽然不是很优雅,但解决方案是在设置 autosaveExpandedItems 和 autoSaveName 之前设置 0.5 秒的延迟。我的应用程序中的半秒延迟并不明显。我也使用了 Vomi 的代码。委托和数据源在 IB 绑定中设置。这是完整的解决方案:
override func viewDidLoad() {
super.viewDidLoad()
let _ = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { (timer) in
self.keywordsOutlineView.autosaveExpandedItems = true
self.keywordsOutlineView.autosaveName = "KeywordsOutlineView"
timer.invalidate()
}
}
func outlineView(_ outlineView: NSOutlineView, persistentObjectForItem item: Any?) -> Any? {
if let node = item as? NSTreeNode {
if let object = node.representedObject as? FTKeyword {
return object.objectID.uriRepresentation().absoluteString
}
}
return nil
}
// This method should return a NSTreeNode object
func outlineView(_ outlineView: NSOutlineView, itemForPersistentObject object: Any) -> Any? {
if outlineView == keywordsOutlineView {
guard let uriAsString = object as? String,
let uri = URL(string: uriAsString) else { return nil }
if let psc = self.managedObjectContext.persistentStoreCoordinator,
let moID = psc.managedObjectID(forURIRepresentation: uri),
let group = self.managedObjectContext.object(with: moID) as? FTKeyword,
let nodes = self.keywordsTreeController.arrangedObjects.children {
return self.findNode(for: group, in: nodes)
}
return nil
}
return nil
}
/// Utility method to find the corresponding NSTreeNode for a given represented object
private func findNode(for object: NSManagedObject, in nodes: [NSTreeNode]) -> NSTreeNode? {
for treeNode in nodes {
if (treeNode.representedObject as? NSManagedObject) === object {
return treeNode
}
}
return nil
}