Я пытаюсь использовать функцию «Автосохранение расширенных элементов». Когда я расширяю группу с ее дочерними элементами и перезапускаю приложение, все дочерние элементы снова сворачиваются, и я не знаю, почему они не останутся расширенными. Я использую основные данные для хранения элементов исходного списка.
Вот что я сделал / установил до сих пор:
- Проверено "Автосохранение расширенных элементов" в 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 ответов
У меня была проблема, что моя реализация -outlineView: itemForPersistentObject: вообще не вызывалась. Оказывается, этот метод вызывается, когда установлено autosaveExpandedItems или autosaveName. Мое решение заключалось в том, чтобы установить оба свойства в Code, а НЕ в InterfaceBuilder. Когда я устанавливаю свойства после назначения делегата, вызывается метод.
Я заставил это работать - вам нужно вернуть соответствующий узел дерева вместо «просто» его представленного объекта.
В 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
, который вы используете для заполнения представления структуры.
Расширяя решение Карстена:
Метод -outlineView:itemForPersistentObject:
вызывается после выполнения того, что предлагает Карстен, но ТОЛЬКО если вы также устанавливаете источник данных перед установкой делегата.
Поэтому, если ответ Карстена не работает, проверьте, где установлен ваш источник данных, и настройте его соответствующим образом.
(хотел написать это как комментарий, но мне не разрешено из-за моего статуса новичка ...)
У меня это никогда не работало.
Это мой нынешний способ сделать это:
Сначала я добавил атрибут 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"];
}
}
Ответ 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
}
managedObjectContext
и persistentStoreCoordinator
. Нашел NSManagedObjectContext
и NSPersistentStoreCoordinator
... Не могли бы вы мне намекнуть?
Ух ты! Спустя 6 лет это все еще вызывает головные боли.
Сначала я не мог заставить это работать, даже с полезным решением Карстена по настройке autoSaveName и autosaveExpandedItems в коде; itemForPersistentObject все еще вызывался до того, как был заполнен контурView. Решение для меня, хотя и не очень элегантное, заключалось в установке задержки 0,5 секунды перед установкой autosaveExpandedItems и autoSaveName. Задержка в полсекунды в моем приложении не заметна. Я тоже использовал код Воми. Делегат и источник данных устанавливаются в привязках 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
}
Похожие вопросы
Новые вопросы
objective-c
Этот тег следует использовать только для вопросов, касающихся функций Objective-C или зависящих от кода на языке. Теги [cocoa] и [cocoa-touch] следует использовать, чтобы узнать о фреймворках или классах Apple. Используйте связанные теги [ios], [macos], [apple-watch] и [tvos] для проблем, характерных для этих платформ.