Блокировка с помощью AFIncrementalStore и NSFetchedResultsController
Я уже несколько дней бьюсь головой об этом и никак не могу понять, что происходит. Я достаточно зелен с Core Data, но знаю это достаточно хорошо, чтобы избежать сценариев тупиковой ситуации. Однако для этого проекта я решил попробовать включить AFIncrementalStore. Я создал пример проекта для тестирования APIClient, чтобы правильно сопоставить ключи / значения, не мешая моему реальному проекту. Работало без нареканий.
Сейчас я использую его в своем реальном проекте, и все очень привередливо. NSFetchedResultsController используется в UITableViewController, который выталкивается за пределы экрана (слайд в меню, похожем на приложение Facebook). Примерно в 50% случаев я не захожу в тупик. Я убедился, что NSFetchedResultsController managedObjectContext совпадает с моим AppDelegate. Почти все настроено идентично примерам AFIncrementalStore. Даже мой пример проекта для тестирования использования отлично работает.
Вот изображение Debug Navigator, когда я делаю паузу во время тупика. Похоже, что проблема лежит между фоновым контекстом AFIncrementalStore и контекстом основного потока. Однако я не уверен, что делать, так как я не писал AFIncrementalStore и просто ухожу из существующих документов / примеров.
редактировать: добавление обратного следа 2-го потока
thread #2: tid = 0x2103, 0x925d180e libsystem_kernel.dylib`semaphore_wait_trap + 10
frame #0: 0x925d180e libsystem_kernel.dylib`semaphore_wait_trap + 10
frame #1: 0x0258cf08 libdispatch.dylib`_dispatch_thread_semaphore_wait + 16
frame #2: 0x0258ab3a libdispatch.dylib`_dispatch_barrier_sync_f_slow + 149
frame #3: 0x0258aa5c libdispatch.dylib`dispatch_barrier_sync_f + 37
frame #4: 0x00b64c8b CoreData`_perform + 187
frame #5: 0x00b67659 CoreData`-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidUnregisterObjectsWithIDs:] + 73
frame #6: 0x00bdf2db CoreData`__97-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidUnregisterObjectsWithIDs:]_block_invoke_0 + 75
frame #7: 0x00b64cc1 CoreData`internalBlockToNSManagedObjectContextPerform + 17
frame #8: 0x0259b014 libdispatch.dylib`_dispatch_client_callout + 14
frame #9: 0x0258ad5f libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 58
frame #10: 0x0258aaa3 libdispatch.dylib`dispatch_barrier_sync_f + 108
frame #11: 0x00b64c8b CoreData`_perform + 187
frame #12: 0x00b67659 CoreData`-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidUnregisterObjectsWithIDs:] + 73
frame #13: 0x00b71c8c CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _disposeObjects:count:notifyParent:] + 444
frame #14: 0x00b71305 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _dispose:] + 597
frame #15: 0x00b70e15 CoreData`-[NSManagedObjectContext _dealloc__] + 325
frame #16: 0x00bd872f CoreData`internalBlockToDeallocNSManagedObjectContext + 79
frame #17: 0x0259b014 libdispatch.dylib`_dispatch_client_callout + 14
frame #18: 0x0258b418 libdispatch.dylib`_dispatch_queue_drain + 239
frame #19: 0x0258b2a6 libdispatch.dylib`_dispatch_queue_invoke + 59
frame #20: 0x0258c280 libdispatch.dylib`_dispatch_root_queue_drain + 231
frame #21: 0x0258c450 libdispatch.dylib`_dispatch_worker_thread2 + 39
frame #22: 0x971cde12 libsystem_c.dylib`_pthread_wqthread + 441
2 ответа
Я не эксперт CoreData ни в коем случае, так что возьмите это с крошкой соли.
Похоже, что вы, возможно, используете NSPrivateQueueConcurrencyType. Похоже, что AFIncrementalStore использует основную очередь для синхронизации. Это под вашим контролем?
Можете ли вы попробовать переключить NSManagedObjectContext на NSMainQueueConcurrencyType и посмотреть, поможет ли это?
Теперь, если я прав, и вы используете NSPrivateQueueConcurrencyType, вы, вероятно, делаете это из соображений производительности. Таким образом, это не может быть отличным долгосрочным решением...
Эта проблема не относится к использованию AFIncrementalStore. Мы сталкивались с тем же самым, просто используя вложенные контексты и контроллер результатов NSFetched.
Дочерний и родственный контексты не должны использовать одни и те же типы параллелизма, не должны использовать один и тот же поток. Однако ваш выбранный контроллер результатов должен использоваться в том же потоке, который использует его контекст управляемого объекта. Тот поток 2 NSManagedObjectContext Queue в вашем отладочном навигаторе заставляет меня думать, что это, вероятно, проблема с многопоточностью.
если это ваш основной контекст, то это так же просто, как обернуть вашу шкуру вот так
dispatch_async(dispatch_get_main_queue(), ^{ [resultsController performFetch:nil]; });
или для действительно параноика
[_resultsController.managedObjectContext performBlock:^{
[_resultsController performFetch:nil];
}];
В этих тупиках много всего, попробуйте здесь и здесь, чтобы получить сообщения о переполнении стека.