Я пытаюсь использовать функцию «Автосохранение расширенных элементов». Когда я расширяю группу с ее дочерними элементами и перезапускаю приложение, все дочерние элементы снова сворачиваются, и я не знаю, почему они не останутся расширенными. Я использую основные данные для хранения элементов исходного списка.

Вот что я сделал / установил до сих пор:

  • Проверено "Автосохранение расширенных элементов" в 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 еще не завершил инициализацию. Есть идеи, как это решить?

7
krema 11 Сен 2014 в 18:03

5 ответов

Лучший ответ

У меня была проблема, что моя реализация -outlineView: itemForPersistentObject: вообще не вызывалась. Оказывается, этот метод вызывается, когда установлено autosaveExpandedItems или autosaveName. Мое решение заключалось в том, чтобы установить оба свойства в Code, а НЕ в InterfaceBuilder. Когда я устанавливаю свойства после назначения делегата, вызывается метод.

3
Karsten 6 Мар 2016 в 15:08

Я заставил это работать - вам нужно вернуть соответствующий узел дерева вместо «просто» его представленного объекта.

В 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
MrMage 17 Июл 2015 в 09:47

Расширяя решение Карстена:

Метод -outlineView:itemForPersistentObject: вызывается после выполнения того, что предлагает Карстен, но ТОЛЬКО если вы также устанавливаете источник данных перед установкой делегата.

Поэтому, если ответ Карстена не работает, проверьте, где установлен ваш источник данных, и настройте его соответствующим образом.

(хотел написать это как комментарий, но мне не разрешено из-за моего статуса новичка ...)

1
Tamás Sengel 15 Сен 2017 в 08:20

У меня это никогда не работало.

Это мой нынешний способ сделать это:

Сначала я добавил атрибут 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"];
    }
}
0
krema 11 Мар 2015 в 10:03

Ответ Swift 5

Карстен прав, 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
}
0
vomi 11 Ноя 2019 в 10:58