Совместим ли NSCollectionView с CoreData?

Обновление: этот поток идентифицирует ошибку в NSCollectionView, когда представленными объектами представления коллекции являются NSManagedObjects. Ошибка срабатывает следующим образом;

(a) Удалить объекты из NSArrayController (b) Выполнить сохранение связанного контекста nsmanagedobjectcontext в любое время после удаления и до того, как NSCollectionView завершит свою анимацию.

Эти проекты на github демонстрируют проблему.

https://github.com/artifacts/NSCollectionViewCoreDataBug https://github.com/iracooke/CoreDataCollectionViewCrashing

Оригинальный вопрос ниже

У меня есть установка NSCollectionView с привязкой содержимого к аранжированным объектам NSArrayController объектов основных данных. В моем представлении элемента коллекции (прототип представления NSCollectionView) у меня есть несколько элементов управления, привязанных через представленный объект моего элемента представления коллекции к моим объектам основных данных.

По большей части это работает нормально.

Я сталкиваюсь с objc_exception, когда пытаюсь удалить объекты из моего ArrayController. Я удаляю эти объекты просто по телефону;

[myArrayController removeObject:managedObjectToDelete];

К сожалению, когда я делаю это, я часто получаю сообщение об ошибке «CoreData не может выполнить ошибку»... с ответственным объектом, являющимся одним из объектов, управляемых NSArrayController.

Изучение стека вызовов при возникновении исключения показывает, что сбой возникает, когда NSCollectionView получает свой метод _endOfAnimation. Это, в свою очередь, инициирует другие методы, связанные с отвязкой (вероятно, свойств моей сущности с элементами управления в моем представлении).

Еще одна информация заключается в том, что Entity, с которой я работаю, не имеет отношения к другим объектам в моей модели.

Мне кажется, что возникает следующая проблема;

  • Когда я удаляю объекты из своего NSArrayController, они, в свою очередь, удаляются из контекста.
  • После удаления из контекста объекты превращаются в разломы
  • NSCollectionView сохранил ссылки на объекты (теперь ошибки). Он пытается очистить их в конце своей анимации (отвязка и т. д.).
  • Когда NSCollectionView пытается очистить привязки к объекту, это приводит к тому, что основные данные пытаются вызвать ошибку на объекте (надеюсь, я правильно понял свою терминологию). Это вызывает ошибку, поскольку объект еще не сохранен на диск.

Единственный способ, который я могу придумать, чтобы предотвратить это, - это сохранить объекты в хранилище (путем их сохранения) перед удалением. Это работает, но только хакерским способом, так как мне нужно убедиться, что один раунд удаления завершен перед повторным сохранением ... и поскольку ошибка возникает во время анимации ... после некоторой задержки ... и два сохранения подряд будут приводит к повторению той же ошибки.

Означает ли это, что я не могу использовать NSArrayController с поддержкой Core-Data для заполнения NSCollectionView? Если нет, то что я делаю неправильно? Есть ли лучший способ решить эту проблему?


person Ira Cooke    schedule 19.01.2011    source источник
comment
Я создал другой проект, демонстрирующий проблему, и зарегистрировал ошибку, это радар № 9903150. Описание проекта и ошибки вы найдете здесь: github.com/artifacts/NSCollectionViewCoreDataBug   -  person    schedule 05.08.2011
comment
Спасибо за это. Ваш проект на github лучше воспроизводит ошибку, чем мой. Я думаю, у Apple есть довольно хорошее описание проблемы из этой темы.   -  person Ira Cooke    schedule 11.08.2011


Ответы (2)


Прямой, но скучный ответ: я могу подтвердить, что NSArrayController, поддерживаемый Core Data, может заполнять NSCollectionView различными объектами GUI в элементе коллекции NSView, связанным с сгенерированным «элементом представления коллекции» и ссылаясь на различные объекты Core Data вдоль пути. Программное удаление (и изменение порядка) элементов NSArrayController работает (с анимацией бесплатно).

Возможно, причиной проблемы являются какие-то привязки или другие зависимости внутри представления коллекции? Или проблема с потоками в контекстах управляемых объектов?

person burton    schedule 28.06.2011
comment
Спасибо. Анимированы ли какие-либо объекты GUI в представлении прототипа? Один из моих — индикатор прогресса. Из памяти отвязка этого объекта вызвала сбой. - person Ira Cooke; 28.06.2011
comment
Возможно, мне следует перефразировать свой вопрос на «Совместим ли NSCollectionView с привязками и основными данными». Ваш ответ, возможно, некоторые привязки вызывают проблему, почти наверняка верен ... но мы должны иметь возможность использовать привязки. +1 за ответ, но это не совсем решает для меня. - person Ira Cooke; 08.07.2011
comment
Мой рабочий код NSCollectionViewItem включает индикатор, который является динамическим и часто обновляется (30 Гц) из сетевого источника, при этом все соединения выполняются через привязки с помощью Interface Builder. Насколько я могу пытаться, я не могу заставить вещи падать, независимо от времени анимации коллекции. Вы привязываетесь только через IB? Что происходит, когда вы удаляете привязку к индикатору прогресса? (чтобы убедиться, что это действительно причина проблемы). На этом этапе некоторый урезанный код, воспроизводящий вашу проблему, поможет точно определить, что происходит. - person burton; 20.07.2011
comment
Спасибо за это продолжение. Вчера вечером я построил минимальный проект и продемонстрировал себе, что он работает идеально, как вы говорите. Я еще не могу воспроизвести свою ошибку, но принимаю этот ответ, потому что в моем коде должно быть что-то еще, вызывающее проблему. Когда я узнаю, что это такое, я опубликую здесь для потомков. - person Ira Cooke; 22.07.2011
comment
Я нашел причину. По-видимому, это невозможно сделать, если вы также сохраните управляемые объекты в другом месте своего кода. Я загрузил мини-проект на github, демонстрирующий проблему. (См. правки к исходному вопросу). - person Ira Cooke; 22.07.2011
comment
я думаю, проблема в том, что вы сохраняете контекст управляемого объекта во время выполнения анимации (удаление сообщения о сохранении устраняет ошибку). Удаление объекта из NSArrayController приводит к тому, что он удаляется из графа объектов Core Data и помечается для удаления, но фактически не удаляется. Удаление объекта выполняется при сохранении. developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ - person burton; 23.07.2011
comment
Ага.. да спасибо. Я обновил проект, чтобы сделать его намного более минимальным. Я думаю, что проблема все еще остается ошибкой, потому что очень сложно гарантировать, что сохранение не выполняется в контексте управляемого объекта во время анимации. Даже если я выполняю сохранение с помощью PerformSelector:afterDelay, я все равно получаю сбой. - person Ira Cooke; 24.07.2011
comment
я согласен с тем, что NSCollectionView мог бы быть более совместным с уведомлениями, но мы начинаем отходить от вопроса... сбой происходит не из-за ошибки ошибки основных данных (которая сама по себе безвредна), а из-за следующего процесса удаления элемента NSArrayController. Вы можете проверить удаленные объекты NSManagedObjectContext в сохранении: и проверить их keepCount и фигуру оттуда, если они все еще хранятся в NSCollectionView перед фактическим выполнением сохранения (и отключить кнопку очистки на время процесса удаления/сохранения). - person burton; 24.07.2011
comment
Я не знаю.. Вам не кажется, что это ошибка? Я должен иметь возможность использовать API основных данных, такие как удаление и сохранение, не думая о том, когда NSCollectionView закончит свою анимацию? В стеке вызовов для сбоя он возникает в методе NSCOllectionView для завершения анимации. Похоже, что NSCollectionView не должен выполнять отвязку в конце анимации, а должен делать это в начале. - person Ira Cooke; 25.07.2011

Вы можете обойти эту проблему, добавив свойство (назначить) в свой CollectionItem, которое указывает на соответствующий ArrayController.

Это свойство можно установить в -[YourNSCollectionViewSubClass newItemWithRepresentedObject:].

Затем вы можете наблюдать аранжированные объекты в каждом элементе. Когда он изменяется и item.representedObject больше не содержится в аранжированных объектах, вы устанавливаете для item.representedObject значение nil. В моем тестировании (10.6.8) это запускает очистку привязки до того, как CoreData превратит объекты в ошибки. (Мои объекты имеют отношения, а представление элементов имеет привязки к ним).

Кстати: эта проблема не ограничивается сохранением во время анимации, ее также могут вызвать комбинации отмены/повторения/сохранения.

Я искал хорошее место, чтобы начать наблюдение внутри элемента, но единственное, что я придумал, было copyWithZone: которого я хотел избежать. (-awakeFromNib вызывается только для первого элемента, -view слишком рано).

Поэтому я (неохотно) решил начать наблюдение в -newItemWithRepresentedObject: и остановить его в -dealloc элемента.

Вы также должны следить за любыми элементами управления или другими действиями, инициируемыми объектами в представлении элементов — быстрым щелчком я мог вызвать сообщения об освобождении объектов, предположительно из-за того, что все еще реагирующие кнопки анимировались под мышью. Мое решение состоит в том, чтобы отключить элементы управления при установке репрезентативного объекта на ноль. YMMV.

Вот мой код наблюдателя:

    - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if( object == self.arrayController && [keyPath isEqualToString: @"arrangedObjects"] ) {
        if( NO == [self.arrayController.arrangedObjects containsObject: self.representedObject] ) {
            self.representedObject = nil;

            for(NSView *subview in [self.view subviews]) {
                if( [subview isKindOfClass: [NSControl class]] ) {
                    [(NSControl *)subview setEnabled: NO];
                }
            }
        }
    } else {
        [super observeValueForKeyPath:keyPath ofObject: object change:change context:context];
    }
}
person Bjoern Kriews    schedule 05.08.2011
comment
Это звучит как хорошее решение, и спасибо, что поделились им. Однако, на мой взгляд, довольно ясно, что NSCollectionView не работает с основными данными, если нам нужно пойти на такие шаги, чтобы предотвратить его сбой. Я думаю, что мне следует отправить отчет об ошибке в Apple по этой теме. - person Ira Cooke; 05.08.2011