奇怪的核心数据在后台线程中崩溃

时间:2011-08-06 11:15:44

标签: multithreading core-data

我有一个后台线程,它持久保存从Core Data中的Web服务下载的JSON数据。这可以按预期工作,除了奇怪和不稳定的场合。我无法确定为什么会发生这种情况,并且无法再现。这在模拟器和设备上都已发生,因此它与内存无关。

崩溃的方法如下;

+ (Hotspot *)insertOrUpdateWithDictionary:(NSDictionary *)hotspotJSON error:(NSError **)error {
NSManagedObjectContext *moc = [[ContentProviderController sharedContentProviderController] managedObjectContext];
Hotspot *hotspot = [Hotspot managedObjectWithPrimaryKey:[hotspotJSON objectForKey:@"id"] error:error];
if (*error == nil) {
    if (hotspot) {
        // Delete hotspot and cascade to other managed objects
        [moc deleteObject:hotspot];
    }
    hotspot = [NSEntityDescription insertNewObjectForEntityForName:@"Hotspot" inManagedObjectContext:moc];
    [hotspot setJSONProperties:hotspotJSON error:error];
} 
if (*error == nil) {
    return hotspot;
}
return nil;

}

managedObjectWithPrimaryKey看起来像这样;

+ (Hotspot *)managedObjectWithPrimaryKey:(NSString *)primaryKey error:(NSError **)error {
if (primaryKey) {
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:[NSEntityDescription entityForName:NSStringFromClass([self class]) inManagedObjectContext:[[ContentProviderController sharedContentProviderController] managedObjectContext] ]];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(hotspotId like %@)", primaryKey];
    [fetchRequest setPredicate:predicate];
    [fetchRequest setFetchLimit:1];
    NSArray *results = [[[ContentProviderController sharedContentProviderController] managedObjectContext] executeFetchRequest:fetchRequest error:error];
    RELEASE_SAFELY(fetchRequest);
    if (*error == nil && results) {
        return ([results count] > 0) ? [results objectAtIndex:0] : nil;
    } else {
        GTMLoggerError(@"error while retrieving process with hotspotId=%@; %@", primaryKey, [*error description]);
        return nil;
    }    
} else {
    *error = [NSError errorWithDomain:kCoreDataPersistenceError code:1000 userInfo:[NSDictionary dictionaryWithObject:@"Attempt to access an Hotspot with an invalid (null) hotspotId." forKey:NSLocalizedDescriptionKey]];
    return nil;
}

}

setJSONProperties只是设置托管对象属性,如下所示;

- (void)setJSONProperties:(NSDictionary *)dictionary error:(NSError **)error {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

//在此处设置热点属性

RELEASE_SAFELY(pool);

}

崩溃日志如下所示;

** Call stack at first throw:
(
    0   CoreFoundation                      0x36b5964f __exceptionPreprocess + 114
    1   libobjc.A.dylib                     0x33db2c5d objc_exception_throw + 24
    2   CoreFoundation                      0x36b58edf __NSFastEnumerationMutationHandler + 214
    3   libobjc.A.dylib                     0x33db936d objc_enumerationMutation + 24
    4   CoreData                            0x36ee5c89 -[NSManagedObjectContext executeFetchRequest:error:] + 1888
    5   magazine                            0x000cd76d +[Page managedObjectWithPrimaryKey:error:] + 288
    6   magazine                            0x000ccc65 -[Hotspot setJSONProperties:error:] + 724
    7   magazine                            0x000cc943 +[Hotspot insertOrUpdateWithDictionary:error:] + 194
    8   magazine                            0x000c3d39 -[ContentProviderController persistHotspots:] + 368
    9   magazine                            0x000c05e5 -[ContentProviderController doPersistenceJobForIssueObjectId:] + 704
    10  CoreFoundation                      0x36b5c7a4 __invoking___ + 68
    11  CoreFoundation                      0x36ad443d -[NSInvocation invoke] + 108
    12  Foundation                          0x34f8043f -[NSInvocationOperation main] + 78
    13  Foundation                          0x34f19d1b -[__NSOperationInternal start] + 658
    14  Foundation                          0x34f19a7f -[NSOperation start] + 22
    15  Foundation                          0x34f7fecb ____startOperations_block_invoke_2 + 46
    16  libdispatch.dylib                   0x339d88e7 _dispatch_call_block_and_release + 10
    17  libdispatch.dylib                   0x339d362d _dispatch_worker_thread2 + 252
    18  libsystem_c.dylib                   0x3483c591 _pthread_wqthread + 264
    19  libsystem_c.dylib                   0x3483cbc4 _init_cpu_capabilities + 4294967295
)

我完全理解在枚举时不应该改变对象,但是我不明白为什么在这个线程中看到一个单独的托管对象(Page) - ([Hotspot setJSONProperties:error:] + 724)。每个托管对象都是按顺序保留的,因此“Page”对象将在此“Hotspot”对象之前保留。

1 个答案:

答案 0 :(得分:0)

好的,事实证明,罪魁祸首是一个非常复杂的事件组合,它产生了两个同时发生的Core Data线程试图对同一数据进行更改。

停止此操作解决了这个问题。