6

Чтобы я не похоронил светодиод, я собираюсь открыть с моим основным вопросом: почему мой массив FetchedObjects NSFetchedResultsController обычно является однородным, но в редких случаях содержит __NSCFString среди управляемых объектов, которые он должен содержать?Почему массив NSFetchedResultsController's fetchedObjects не всегда однородный

У меня есть приложение, которое работает в течение долгого времени. Основной вид - это табличное представление, которое содержит список видео, поддерживаемых основными объектами, управляемыми данными. Контроллер табличные использует NSFetchedResultsController сконфигурированные с довольно обычным NSFetchRequest:

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:[ABCVideo entityName]]; 
NSString *sectionKeyPath = nil; 
request.fetchBatchSize = 20; 
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:ABCVideoAttributes.recordingDate ascending:NO]; 
      sectionKeyPath = @"sectionIdentifier"; 
request.sortDescriptors = @[sort]; 
request.predicate = [NSPredicate predicateWithFormat:@"owner = %@ and %K = %@", person, ABCVideoAttributes.serverDeleted, @(NO)]; 
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:moc sectionNameKeyPath:sectionKeyPath cacheName:kABCMyVideosTableViewControllerCacheKey]; 

Поскольку это видео может быть загружено в облако, этот вид таблицы контроллер получает случайные уведомления обновить прогресс бары в представлении ячейки таблицы, соответствующая видео которые в настоящее время загружаются. Внутри этого обратного вызова мы получаем массив fetchedObjects, чтобы найти видео, соответствующее уведомлению, так что правильная ячейка представления таблицы может обновить индикатор выполнения.

Все это работает. 99,9% времени, он работает каждый раз </RonBurgundy>.

Но я заметил в наших отчетах о сбоях HockeyApp, что редкий, редкий случай, когда я получал SIGABRT, что происходит, когда мой обработчик уведомлений пытается получить filteredArrayUsingPredicate от fetchedObjects:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0x136f24480> valueForUndefinedKey:]: this class is not key value coding-compliant for the key guid.'

Недавно мне удалось найти случай, когда я мог бы иногда воспроизвести этот крах, и после большого количества экспериментов я обнаружил, что в массиве fetchedObjects иногда содержалось то, что не было ABCVideo: вместо этого один слот в массиве был занят __NSCFString экземпляр. Это было довольно удивительно, учитывая, что NSFetchRequestResultType имеет значение NSManagedObjectResultType, а строка не является управляемым объектом.

Так что мне осталось интересно: это ошибка ядра? Или мой массив содержит указатель, который ранее указывал на экземпляр ABCVideo, который был освобожден, и что место в куче впоследствии было взято экземпляром __NSCFString? Если это последний, то как это могло произойти? Я использую ARC, поэтому трудно понять, как одно из этих видео может быть освобождено.

+0

Я подозреваю, что ошибка Core Data. В iOS9 появилось несколько ошибок, особенно с NSFetchedResultsControllers, и это может быть другое. – Avi

+0

Сам массив должен сохранять свои объекты, поэтому, если вы каким-то образом не освобождаете слишком много, их не следует освобождать. Кроме того, с ARC это почти наверняка не так. Может быть ошибкой ARC или ошибкой Core Data. Можете ли вы исключить, что это связано с кэшированием с помощью 'NSFetchedResultsController'? Отключить кеширование и воспроизведение? – SmokeDispenser

+0

Поскольку вы можете воспроизвести его, может быть полезно обнаружить, когда это произойдет, и проверить содержимое строки. Я не знаю, почему строка есть, но ее содержимое может указывать на причину. –

ответ

4

Ошибка в управлении памятью в -[NSFetchedResultsController fetchedObjects] с NSFastEnumeration. Объект 0x136f24480 был ABCVideo, но освобожден. Этот кусок памяти использовался для хранения __NSCFString. Общий результат - отправка сообщений неверным объектам, EXC_BAD_ACCESS и SIGABRT.

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

Существует несколько способов обхода проблемы. Ключ, чтобы избежать NSFastEnumeration на fetchedObjects

// 1 
NSArray *fetchedObjects = controller.fetchedObjects 
for (int i = 0; i < fetchedObjects.count; ++i) { 
    NSManagedObject *object = fetchedObjects[i]; 
} 

// 2 
NSArray <id<NSFetchedResultsSectionInfo>> *sections = controller.sections; 
for (int s = 0; s < sections.count; ++s) { 
    id<NSFetchedResultsSectionInfo> section = sections[s]; 
    for (int i = 0; i < [section numberOfObjects]; ++i) { 
     NSManagedObject *object = [controller objectAtIndexPath:[NSIndexPath indexPathForItem:i inSection:s]]; 
    } 
} 

// 3 Fetch from NSManagedContextDirectly 

Если, к сожалению, кто-то читает это с помощью Swift, вы получите сбои даже призывающих fetchedObjects, потому что Swift преобразует NSArray в Array используя NSFastEnumeration.

+0

Это не отвечает на вопрос. Если у вас есть другой вопрос, вы можете задать его, нажав [Ask Question] (http://stackoverflow.com/questions/ask). Вы также можете [добавить щедрость] (http://stackoverflow.com/help/privileges/set-bounties), чтобы привлечь больше внимания к этому вопросу. - [Из обзора] (/ review/low-quality-posts/11031964) – ChrisStillwell

+1

@ChrisStillwell Я не уверен, что понимаю, откуда вы. Как автор вопроса, я бы счел это ответом на мой вопрос, если это правда. (Почему массив не является однородным? Поскольку ложные указатели на выпущенные объекты по совпадению указывают на вещи с другими типами). – pohl

+0

Эта ошибка существует с iOS 8.x. Я не уверен, был ли кто-нибудь, кто сообщил об этом Apple. Я предполагаю, что, по крайней мере, у репортера не было никаких образцов проектов для Apple. Apple любит притворяться, что ошибок нет, если нет примеров проектов. – keithyip

Смежные вопросы