Bloqueo en setValue: forKey:

Crashlytics informó de un locking en mi aplicación, y no tengo idea de lo que está sucediendo.

Aquí está el stacktrace:

Thread : Fatal Exception: NSInternalInconsistencyException 0 CoreFoundation 0x30080e83 __exceptionPreprocess + 130 1 libobjc.A.dylib 0x3a3dd6c7 objc_exception_throw + 38 2 CoreData 0x2fdcf941 -[NSSQLiteStatement cachedSQLiteStatement] 3 CoreData 0x2fdcf18d -[NSSQLiteConnection prepareSQLStatement:] + 52 4 CoreData 0x2fde8edf -[NSSQLChannel selectRowsWithCachedStatement:] + 58 5 CoreData 0x2fea8e1f newFetchedRowsForFetchPlan_MT + 910 6 CoreData 0x2fde8949 -[NSSQLCore fetchRowForObjectID:] + 1180 7 CoreData 0x2fde8311 -[NSSQLCore newValuesForObjectWithID:withContext:error:] + 256 8 CoreData 0x2fde762b _PFFaultHandlerLookupRow + 398 9 CoreData 0x2fde7193 _PF_FulfillDefernetworkingFault + 218 10 CoreData 0x2fdf6449 _PF_ManagedObject_WillChangeValueForKeyIndex + 68 11 CoreData 0x2fdf636b _shanetworkingIMPL_setvfk_core + 110 12 CoreData 0x2fe1995d _PF_Handler_Public_SetProperty + 92 13 CoreData 0x2fe1e2a9 -[NSManagedObject setValue:forKey:] + 124 14 Application 0x0004dc45 -[DateFormatter storeValue:error:] (DateFormatter.m:65) 15 Application 0x0004ee17 -[Formatter storeValue:inObject:] (Formatter.m:176) 16 Application 0x0002b5c5 -[NSManagedObject(App) setValuesForKeysWithReceivedDictionary:] (NSManagedObject+App.m:320) 17 Application 0x0002b8f3 -[NSManagedObject(App) setValuesForKeysWithReceivedDictionary:] (NSManagedObject+App.m:377) 18 Application 0x0006352d -[ODataGetOperation processResult:] (ODataGetOperation.m:220) 19 Application 0x0004420b -[ODataOperation connectionDidFinishLoading:] (ODataOperation.m:741) 20 Foundation 0x309bb47f __65-[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:]_block_invoke + 54 21 Foundation 0x309bb3c1 -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] + 204 22 Foundation 0x309bb2dd -[NSURLConnectionInternal _withActiveConnectionAndDelegate:] + 60 23 CFNetwork 0x2fceaf8f ___ZN27URLConnectionClient_Classic26_delegate_didFinishLoadingEU13block_pointerFvvE_block_invoke + 74 24 CFNetwork 0x2fce9b8f ___ZN27URLConnectionClient_Classic18_withDelegateAsyncEPKcU13block_pointerFvP16_CFURLConnectionPK33CFURLConnectionClientCurrent_VMaxE_block_invoke_2 + 54 25 CFNetwork 0x2fd1b337 ___ZNK17CoreSchedulingSet13_performAsyncEPKcU13block_pointerFvvE_block_invoke + 18 26 CoreFoundation 0x2ffb3ea1 CFArrayApplyFunction + 36 27 CFNetwork 0x2fc81e05 RunloopBlockContext::perform() + 164 28 CFNetwork 0x2fc81cd5 MultiplexerSource::perform() + 220 29 CFNetwork 0x2fc81b65 MultiplexerSource::_perform(void*) + 48 30 CoreFoundation 0x3004bf1f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 14 31 CoreFoundation 0x3004b3e7 __CFRunLoopDoSources0 + 206 32 CoreFoundation 0x30049bd7 __CFRunLoopRun + 630 33 CoreFoundation 0x2ffb4471 CFRunLoopRunSpecific + 524 34 CoreFoundation 0x2ffb4253 CFRunLoopRunInMode + 106 35 Foundation 0x309a2697 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 254 36 Application 0x00043b4b -[ODataOperation send] (ODataOperation.m:548) 37 Application 0x0004277f -[ODataOperation operationWillStartPreparingData] (ODataOperation.m:131) 38 Foundation 0x30a5396d __NSOQSchedule_f + 60 39 libdispatch.dylib 0x3a8c64b7 _dispatch_async_networkingirect_invoke + 110 40 libdispatch.dylib 0x3a8c77d9 _dispatch_root_queue_drain + 224 41 libdispatch.dylib 0x3a8c79c5 _dispatch_worker_thread2 + 56 42 libsystem_pthread.dylib 0x3a9f1dff _pthread_wqthread + 298 43 libsystem_pthread.dylib 0x3a9f1cc4 start_wqthread + 8 

Y existe el último método que llama a setValue: forKey: en una subclass NSManagedObject

 - (BOOL)storeValue:(void *)theValue error:(NSError **)theError { NSString * value = (__bridge NSString *)theValue; NSString * errorMessage = nil; if (![value length] && !isOptional) errorMessage = [NSString stringWithFormat: NSLocalizedString(@"Value cannot be nil or empty (Date) for field %@", @""), varName]; else { NSDate * date = nil; if ([value length]) { date = [NSDate dateWithISO8601: value]; if (!date) errorMessage = [NSString stringWithFormat: NSLocalizedString(@"Invalid date %@ for field %@", @""), theValue, varName]; } if (IvarAddress) *((__strong NSDate **) IvarAddress) = date; else [currentObject setValue: date forKey: varName]; } if (errorMessage) { if (theError) *theError = [NSError errorWithDomain: AppDomain code: NSFormattingError userInfo: @{ NSLocalizedDescriptionKey: errorMessage }]; #ifdef DEBUG NSLog(@"Formatter error: %@", errorMessage); #endif return NO; } return YES; } 

Estoy completamente abierto a cualquier sugerencia 🙂

Actualización: la key existe y el valor que se establece es un NSDate, por lo que es un atributo de NSManagedObject, no una relación.

Actualización 2:

También tengo otro locking con ese método (el rastreo de stack no es exactamente el mismo):

 Thread : Fatal Exception: NSInternalInconsistencyException 0 CoreFoundation 0x30080e83 __exceptionPreprocess + 130 1 libobjc.A.dylib 0x3a3dd6c7 objc_exception_throw + 38 2 CoreData 0x2fddfacb -[NSSQLCore _obtainOpenChannel] + 234 3 CoreData 0x2fea8ded newFetchedRowsForFetchPlan_MT + 860 4 CoreData 0x2fde8949 -[NSSQLCore fetchRowForObjectID:] + 1180 5 CoreData 0x2fde8311 -[NSSQLCore newValuesForObjectWithID:withContext:error:] + 256 6 CoreData 0x2fde762b _PFFaultHandlerLookupRow + 398 7 CoreData 0x2fde7193 _PF_FulfillDefernetworkingFault + 218 8 CoreData 0x2fdf6449 _PF_ManagedObject_WillChangeValueForKeyIndex + 68 9 CoreData 0x2fdf636b _shanetworkingIMPL_setvfk_core + 110 10 CoreData 0x2fe1995d _PF_Handler_Public_SetProperty + 92 11 CoreData 0x2fe1e2a9 -[NSManagedObject setValue:forKey:] + 124 12 Application 0x000fcc45 -[DateFormatter storeValue:error:] (DateFormatter.m:65) 13 Application 0x000fde17 -[Formatter storeValue:inObject:] (Formatter.m:176) 14 Application 0x000da5c5 -[NSManagedObject(App) setValuesForKeysWithReceivedDictionary:] (NSManagedObject+.m:320) 15 Application 0x000da8f3 -[NSManagedObject(App) setValuesForKeysWithReceivedDictionary:] (NSManagedObject+.m:377) 16 Application 0x0011252d -[ODataGetOperation processResult:] (ODataGetOperation.m:220) 17 Application 0x000f320b -[ODataOperation connectionDidFinishLoading:] (ODataOperation.m:741) 18 Foundation 0x309bb47f __65-[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:]_block_invoke + 54 19 Foundation 0x309bb3c1 -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] + 204 20 Foundation 0x309bb2dd -[NSURLConnectionInternal _withActiveConnectionAndDelegate:] + 60 

El post de exception también es diferente:

_obtainOpenChannel – NSSQLCore 0x15ef3780: no hay ningún canal de database disponible

Pero creo que son dos cuestiones relacionadas.

Así que finalmente encontré los motivos que estaban relacionados con los problemas de multihilo / concurrency. Básicamente, actualiza los mismos objects en dos subprocesss al mismo time.

Los indicadores de debugging de datos centrales recientemente agregados (-com.apple.CoreData.ConcurrencyDebug 1) se utilizaron para descubrir qué estaba sucediendo.