开发者

Odd Core Data crash in background thread

开发者 https://www.devze.com 2023-03-26 03:23 出处:网络
I have a background thread persisting JSON data downloaded from a web service in Core Data. This works as expected, except for odd and erratic occasions. I have not been able to identify why this occu

I have a background thread persisting JSON data downloaded from a web service in Core Data. This works as expected, except for odd and erratic occasions. I have not been able to identify why this occurs, and can cannot reproduce. This has occurred on both the simulator and on the device, so it is not memory related.

The method that crashes is as follows;

+ (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 c开发者_开发问答ascade 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 looks like this;

+ (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 is simply setting the managed object properties as follow;

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

//set hotspot properties here

RELEASE_SAFELY(pool);

}

The crash logs looks as follows;

** 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
)

I fully understand that an object should not be mutated while enumerating, but what I don't understand is why a separate managed object(Page) is seen in this thread(-[Hotspot setJSONProperties:error:] + 724). Each managed object is persisted sequentially, so a "Page" object would have been persisted before this "Hotspot" object.


Okay, so it turns out that the culprit was a very complex combination of events that spawned two simultaneous Core Data threads trying to make changes to the same data.

Stopping this solved the problem.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号