dispatch_sync()
メイン キューでブロックを実行しています。このブロックでは、executeFetchRequest:error:
最終的に への呼び出しが行われます。場合によっては、これによりデッドロックが発生します。
これは、メイン スレッドで呼び出されたブロックと、次の呼び出しを示すスレッド 1 です。executeFetchRequest:error:
#0 0x981f3876 in __psynch_mutexwait ()
#1 0x97a016af in pthread_mutex_lock ()
#2 0x0135be32 in -[_PFLock lock] ()
#3 0x0135be0a in -[NSPersistentStoreCoordinator lock] ()
#4 0x01371d1c in -[NSManagedObjectContext(_NSInternalAdditions) lockObjectStore] ()
#5 0x013702c0 in -[NSManagedObjectContext executeFetchRequest:error:] ()
#6 0x0000a701 in -[NSManagedObjectContext(Convenience) fetchObjectsForEntityName:onlyIDs:withPredicate:] at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/NSManagedObjectContext(Convenience).m:50
#7 0x00065270 in +[NSManagedObject(ContextAdditions) contextForID:managedObjectContext:] at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/NSManagedObject+ContextAdditions.m:40
#8 0x0006597e in __85+[NSManagedObject(ContextAdditions) createContextIfNeededForID:managedObjectContext:]_block_invoke_0 at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/NSManagedObject+ContextAdditions.m:55
#9 0x00065aad in __85+[NSManagedObject(ContextAdditions) createContextIfNeededForID:managedObjectContext:]_block_invoke_050 at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/NSManagedObject+ContextAdditions.m:64
#10 0x023cf8d9 in _dispatch_barrier_sync_f_slow_invoke ()
#11 0x023d0509 in _dispatch_main_queue_callback_4CF ()
#12 0x01ae9803 in __CFRunLoopRun ()
#13 0x01ae8d84 in CFRunLoopRunSpecific ()
#14 0x01ae8c9b in CFRunLoopRunInMode ()
#15 0x019b47d8 in GSEventRunModal ()
#16 0x019b488a in GSEventRun ()
#17 0x004ba626 in UIApplicationMain ()
executeFetchRequest:error:
が のロックをブロックしていることNSPersistentStoreCoordinator
はわかりますが、現在誰がロックしているのかわかりません。
オリジナルdispatch_sync()
は別のスレッドから発生しています。重要な場合は次のとおりです。
Thread 18, Queue : (null)
#0 0x981f1c5e in semaphore_wait_trap ()
#1 0x023d1bda in _dispatch_thread_semaphore_wait ()
#2 0x023d0cb2 in _dispatch_barrier_sync_f_slow ()
#3 0x023d0e0f in dispatch_barrier_sync_f ()
#4 0x023d0f4c in _dispatch_sync_slow ()
#5 0x0006563a in +[NSManagedObject(ContextAdditions) createContextIfNeededForID:managedObjectContext:] at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/NSManagedObject+ContextAdditions.m:63
#6 0x0006e2ee in __109-[ItemFetcher createOrConfigureObjectWithDescriptor:withContext:jsonObjectIDKey:modelObjectIDKey:entityName:]_block_invoke_0 at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/ItemFetcher.m:78
#7 0x023ce330 in _dispatch_call_block_and_release ()
#8 0x023cff0c in _dispatch_queue_drain ()
#9 0x023cfcb4 in _dispatch_queue_invoke ()
#10 0x023cf402 in _dispatch_worker_thread2 ()
#11 0x97a04b24 in _pthread_wqthread ()
元のディスパッチまでのコードは次のとおりです。
+ (Context *) createContextIfNeededForID: (NSString *) contextID managedObjectContext:(NSManagedObjectContext *) moc
{
// See if this context is in the main MOC. This call needs to happen synchronously on the main queue, if we're
// not on the main queue
Context * (^contextFromMainMOCBlock)(void) =
^ `Context` * {
// We are guaranteed to be in the main here; look at how this block is invoked.
return [self contextForID:contextID managedObjectContext:[UIApplication trackyAppDelegate].managedObjectContext] ;
} ;
__block Context *contextFromMainMOC = nil ;
if( [UIApplication trackyAppDelegate].managedObjectContext == moc )
contextFromMainMOC = contextFromMainMOCBlock() ;
else
dispatch_sync(dispatch_get_main_queue(), ^{
contextFromMainMOC = contextFromMainMOCBlock() ; // <-- here
}) ;
…
contextForID:contextID managedObjectContext:
を呼び出すまで、コア データに対して実際には何もしませんexecuteFetchRequest:error:
。
アップデート
残りのスタック トレースは次のとおりです。私が間違っているかもしれませんが、彼らは何も面白いことをしていません。
Thread 3, Queue : (null)
#0 0x981f490a in kevent ()
#1 0x023d0372 in _dispatch_mgr_invoke ()
#2 0x023cebe1 in _dispatch_mgr_thread ()
Thread 5 WebThread, Queue : (null)
#0 0x981f1c22 in mach_msg_trap ()
#1 0x981f11f6 in mach_msg ()
#2 0x01b8610a in __CFRunLoopServiceMachPort ()
#3 0x01ae95d5 in __CFRunLoopRun ()
#4 0x01ae8d84 in CFRunLoopRunSpecific ()
#5 0x01ae8c9b in CFRunLoopRunInMode ()
#6 0x04776420 in _ZL12RunWebThreadPv ()
#7 0x97a02ed9 in _pthread_start ()
Thread 6 com.apple.NSURLConnectionLoader, Queue : (null)
#0 0x981f1c22 in mach_msg_trap ()
#1 0x981f11f6 in mach_msg ()
#2 0x01b8610a in __CFRunLoopServiceMachPort ()
#3 0x01ae95d5 in __CFRunLoopRun ()
#4 0x01ae8d84 in CFRunLoopRunSpecific ()
#5 0x01ae8c9b in CFRunLoopRunInMode ()
#6 0x00ebae30 in +[NSURLConnection(Loader) _resourceLoadLoop:] ()
#7 0x00dcc4d6 in -[NSThread main] ()
#8 0x00dcc447 in __NSThread__main__ ()
#9 0x97a02ed9 in _pthread_start ()
Thread 10 com.apple.CFSocket.private, Queue : (null)
#0 0x981f3b42 in select$DARWIN_EXTSN ()
#1 0x01b1a7cb in __CFSocketManager ()
#2 0x97a02ed9 in _pthread_start ()
contextID:managedObjectContext:
で呼び出されるメソッドは次のとおりdispatch_sync()
です。
+ (Context *) contextForID: (NSString *) contextID managedObjectContext:(NSManagedObjectContext *) moc
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"cid == %@", contextID] ;
NSSet *contexts = [moc fetchObjectsForEntityName:@"Context" onlyIDs:NO withPredicate:predicate] ;
// Integrity check
NSAssert1(contexts.count < 2, @"More than one context with the same CID exists: %@" , contexts) ;
return [contexts anyObject] ;
}
fetchObjectsForEntityName:onlyIDs:withPredicate:
次のようになります。
- (NSSet *)fetchObjectsForEntityName:(NSString *)newEntityName onlyIDs: (BOOL) onlyIDs
withPredicate:(id)stringOrPredicate, ...
{
NSEntityDescription *entity = [NSEntityDescription
entityForName:newEntityName inManagedObjectContext:self];
NSAssert1( entity != nil , @"entity not found for \"%@\"" , newEntityName ) ;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setIncludesPropertyValues:!onlyIDs] ;
if (stringOrPredicate)
{
NSPredicate *predicate;
if ([stringOrPredicate isKindOfClass:[NSString class]])
{
va_list variadicArguments;
va_start(variadicArguments, stringOrPredicate);
predicate = [NSPredicate predicateWithFormat:stringOrPredicate
arguments:variadicArguments];
va_end(variadicArguments);
}
else
{
NSAssert2([stringOrPredicate isKindOfClass:[NSPredicate class]],
@"Second parameter passed to %s is of unexpected class %@",
sel_getName(_cmd), NSStringFromClass(stringOrPredicate));
predicate = (NSPredicate *)stringOrPredicate;
}
[request setPredicate:predicate];
}
NSError *error = nil;
NSArray *results ;
@try {
results = [self executeFetchRequest:request error:&error];
}
@catch (NSException *exception) {
NSLog(@"Exception caught: %@" , exception) ;
}
if (error != nil)
{
[NSException raise:NSGenericException format:@"%@",[error description]];
}
return [NSSet setWithArray:results];
}