У меня проблема, которая почти идентична проблеме, описанной этим человеком здесь, но на нее нет ответа:
Вот проблема:
У меня есть родительская настройка MOC с NSPrivateQueueConcurrencyType и набор постоянных хранителей хранилища, у нее есть настройка MOC для детей с NSMainQueueConcurrencyType. Идея, заключающаяся в большой длительной работе и экономии, может быть выполнена на частном MOC, освобождающем основной поток от блокировки пользовательского интерфейса. К сожалению, я, похоже, сталкиваюсь с несколькими ситуациями, которые вызывают взаимоблокировки.
Если дочерний MOC (в основном потоке) выполняет выборку с помощью NSFetchedResultsController, родительский контекст отправляется -executeFetchRequest: он может создать тупик. Обе операции выполняются в контексте executeBlock: для соответствующих MOC, хотя документы, похоже, указывают на то, что использование основного потока concurrency типа MOC в основном потоке без executeBlock: отлично.
Похоже, что частная очередь ждет блокировки PSC, которая уже заблокировала дочерний контекст в основном потоке. Похоже, что дочерний контекст (удерживая блокировку PSC) пытается dispatch_sync в родительский контекст, и поэтому они оба ждут друг друга.
Является ли PriveQueue → MainQueue поддерживаемой конфигурацией? Кажется, что большинство людей по-прежнему имеют родительский контекст в основном потоке.
Основной поток выглядит следующим образом:
> #0 0x960f6c5e in semaphore_wait_trap () > #1 0x04956bb5 in _dispatch_thread_semaphore_wait () > #2 0x04955c8f in _dispatch_barrier_sync_f_slow () > #3 0x04955dea in dispatch_barrier_sync_f () > #4 0x01797de5 in _perform () > #5 0x01798547 in -[NSManagedObjectContext(_NestedContextSupport) newValuesForObjectWithID:withContext:error:] () > #6 0x0176416b in _PFFaultHandlerLookupRow () > #7 0x01763f97 in -[NSFaultHandler fulfillFault:withContext:forIndex:] () > #8 0x01763b75 in _PF_FulfillDeferredFault () > #9 0x017639f2 in _sharedIMPL_pvfk_core () > #10 0x017681a0 in _pvfk_11 () > #11 0x0001b322 in -[FBUser sectionName] at /Users/mlink/Code/x/x/FBUser.m:62 > #12 0x011a8813 in _NSGetUsingKeyValueGetter () > #13 0x017a0652 in -[NSManagedObject valueForKey:] () > #14 0x011ab8d5 in -[NSObject(NSKeyValueCoding) valueForKeyPath:] () > #15 0x01851f72 in -[NSFetchedResultsController(PrivateMethods) _sectionNameForObject:] () > #16 0x01853af6 in -[NSFetchedResultsController(PrivateMethods) _computeSectionInfo:error:] () > #17 0x01850ea6 in -[NSFetchedResultsController performFetch:] () > #18 0x0003a4fc in __62-[SYFriendsTableViewController updateFetchedResultsController]_block_invoke_0 () > #19 0x01797af3 in developerSubmittedBlockToNSManagedObjectContextPerform () > #20 0x049554f0 in _dispatch_main_queue_callback_4CF () > #21 0x01b3e833 in __CFRunLoopRun () > #22 0x01b3ddb4 in CFRunLoopRunSpecific () > #23 0x01b3dccb in CFRunLoopRunInMode () > #24 0x023d6879 in GSEventRunModal () > #25 0x023d693e in GSEventRun () > #26 0x0089aa9b in UIApplicationMain () > #27 0x00002656 in main at /Users/mlink/Code/x/x/main.mm:16
стек частной очереди выглядит следующим образом:
#0 0x960f8876 in __psynch_mutexwait ()
#1 0x97e9e6af in pthread_mutex_lock ()
#2 0x0172ec22 in -[_PFLock lock] ()
#3 0x0172ebfa in -[NSPersistentStoreCoordinator lock] ()
#4 0x01746a8c in -[NSManagedObjectContext(_NSInternalAdditions) lockObjectStore] ()
#5 0x01745030 in -[NSManagedObjectContext executeFetchRequest:error:] ()
#6 0x0009d49f in -[NSManagedObjectContext(Additions) executeFetchRequest:] at /Users/mlink/Code/objc/C/C/NSManagedObjectContext+Additions.m:44
#7 0x0002177f in +[FBUser usersForFbids:inManagedObjectContext:] at /Users/mlink/Code/x/x/FBUser.m:435
#8 0x00021fc0 in __77+[FBUser updateUserFromGraphValues:inManagedObjectContext:completionHandler:]_block_invoke_0 at /Users/mlink/Code/x/x/FBUser.m:461
#9 0x0180f9f3 in developerSubmittedBlockToNSManagedObjectContextPerform_privateasync ()
#10 0x04954ecf in _dispatch_queue_drain ()
#11 0x04954d28 in _dispatch_queue_invoke ()
#12 0x049544af in _dispatch_worker_thread2 ()
#13 0x97ea1b24 in _pthread_wqthread ()
#14 0x97ea36fe in start_wqthread ()
Он также пишет следующее:
Я начинаю думать, что проблема связана с NSFetchedResultsController, который всегда застревает в performFetch: когда происходят эти взаимоблокировки. Большую часть времени он будет застревать, пытаясь вызвать ошибку в объекте в результате запроса имени раздела. В качестве теста я попытался воспроизвести, что делает FRC и выполнил executeFetchRequest, а затем повторил результаты, прося каждый объект для этого имени раздела. И это не вызывает тупика. Если я покину FRC, чтобы выполнить performFetch: после того, как я сделаю свой тест, он все равно закроется. Я на 99% уверен, что FRC имеет проблему синхронизации с вложенными контекстами.
Вопрос: Кто-нибудь знает, почему эта проблема возникает? Вы знаете, как его решить? Это ошибка?