Вопрос

I have a function, lets just call it the "Update Function", that sends an RKManagedObjectRequestOperation to my server to retrieve some objects. I configured this operation to automatically saveToPersistentStore, and then I start it. In the 'success' completion handler of the RKManagedObjectRequestOperation I call a function that does an NSFetchRequest to get an updated list of objects that meets certain criteria, and pass back that array and a BOOL flag if there was new data in a completion block.

In the completion handler of the "Update Function" I call a function called getUpdatedList, which does an NSFetchRequest request like so:

    NSUInteger now = [[NSDate date] timeIntervalSince1970];

    NSArray *predicates = @[
                            [NSPredicate predicateWithFormat:@"endAt > %d", now],
                            [NSPredicate predicateWithFormat:@"deleted != %@", @YES]
                            ];

    NSManagedObjectContext *managedObjectContext = [self managedObjectContext]; //(REMOVED: _objectManager.managedObjectStore.persistentStoreManagedObjectContext;)

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];

    NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
    [fetchRequest setPredicate:compoundPredicate];

    NSError *error = nil;

    NSArray *fetchedRecords = [managedObjectContext executeFetchRequest:fetchRequest error:&error];

    if (sortDescriptor) {
        fetchedRecords = [fetchedRecords sortedArrayUsingDescriptors:@[sortDescriptor]];
    }

    DDLogInfo(@"Retrieving list of %@ objects from local database - got %d results.", entityName, fetchedRecords.count);

    return fetchedRecords;

- (NSManagedObjectContext *)managedObjectContext {
    if (_globalContext != nil) {
        return _globalContext;
    }

    NSPersistentStoreCoordinator *coordinator = _objectManager.managedObjectStore.persistentStoreCoordinator;
    if (coordinator != nil) {
        _globalContext = [[NSManagedObjectContext alloc] init];
        [_globalContext setPersistentStoreCoordinator:coordinator];
    }
    return _globalContext;
}

Now, I've never personally seen this crash myself, so I don't know exactly what's going on, but in my logs I get to the point where it says "Retrieving list of %@ objects from local database - got x results.", and then the logging will start over again which happens when the app crashes. Somewhere in the midst of this RKManagedObjectRequestOperation and returning the updated list, the app crashes like 1/1000 times...

Below is one of the stack traces I got from Crashlytics. There are a number of functions that call the 'Update Function', some from the background, some while in the foreground, but all of the stack traces reference this 'Update Function" which you can see on line 9 below (updateAndFetchInfoWithCompletionHandler):

    Thread : com.apple.uikit.backgroundTaskAssertionQueue
0  libsystem_kernel.dylib         0x38911a50 mach_msg_trap + 20
1  libsystem_kernel.dylib         0x3891184d mach_msg + 40
2  SpringBoardServices            0x34d2b42d SBGetBackgroundTimeRemaining + 52
3  SpringBoardServices            0x34d29461 SBSGetBackgroundTimeRemaining + 36
4  UIKit                          0x30685b23 __40-[UIApplication backgroundTimeRemaining]_block_invoke + 10
5  libdispatch.dylib              0x38858d3f _dispatch_client_callout + 22
6  libdispatch.dylib              0x3885d6c3 _dispatch_barrier_sync_f_invoke + 26
7  UIKit                          0x30685a97 -[UIApplication backgroundTimeRemaining] + 182
8  <redacted>                     0x002345df __46-[LocationManager handleExitedRegion]_block_invoke_2 (LocationManager.m:262)
9  <redacted>                     0x002451e3 __57-[DataManager updateAndFetchInfoWithCompletionHandler:]_block_invoke (DataManager.m:719)
10 <redacted>                     0x00340d0d __66-[RKObjectRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke229 (RKObjectRequestOperation.m:506)
11 libdispatch.dylib              0x38858d53 _dispatch_call_block_and_release + 10
12 libdispatch.dylib              0x38858d3f _dispatch_client_callout + 22
13 libdispatch.dylib              0x3885b6c3 _dispatch_main_queue_callback_4CF + 278
14 CoreFoundation                 0x2dba3681 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8
15 CoreFoundation                 0x2dba1f4d __CFRunLoopRun + 1308
16 CoreFoundation                 0x2db0c769 CFRunLoopRunSpecific + 524
17 CoreFoundation                 0x2db0c54b CFRunLoopRunInMode + 106
18 GraphicsServices               0x32a796d3 GSEventRunModal + 138
19 UIKit                          0x3046b891 UIApplicationMain + 1136
20 <redacted>                     0x000a3197 main (main.m:18)

Is there something obvious here that I'm missing that's causing all these crashes?

EDIT: changed the above code to reflect a different managed object context after comments.

Это было полезно?

Решение

You shouldn't be using persistentStoreManagedObjectContext. If this code is running on the main thread then you must use the main queue context. If running on an arbitrary background thread then you must create a new context specifically for that invocation.

Contexts are thread specific and you must respect the thread ownership of each context you create.

When running on a background thread, create a new context with newChildManagedObjectContextWithConcurrencyType:tracksChanges:. This maintains the thread restrictions required by the context.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top