自动保存NSOutlineView的扩展项目不起作用

时间:2014-09-11 14:03:53

标签: objective-c nsoutlineview

我正在尝试使用“自动保存扩展项目”功能。当我使用其子项扩展组并重新启动应用程序时,所有子项都会再次崩溃,我不知道为什么它们不会保持扩展状态。 我正在使用核心数据来存储我的源列表项。

这就是我到目前为止所做的事情:

  • 在NSOutlineView(来源列表)
  • 中选中“自动保存扩展项目”
  • 设置“自动保存”的名称
  • 分配给我的控制器的dataSource和委托出口

这是我对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尚未完成初始化。任何想法如何解决这个问题?

6 个答案:

答案 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"并为每个节点保存数据库中的状态。

enter image description here

其次,我在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
}