RestKit: 'NSInternalInconsistencyException'

2019-09-08 04:44发布

问题:

I'm getting the following error:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Unable to perform mapping: No `managedObjectContext` assigned. (Mapping response.URL = https://www.someurl.com/lastrequest=2014-12-08T02%3A44%3A52Z)'

The app stops at the following line in RKResponseMapperOperation.m:

- (RKMappingResult *)performMappingWithObject:(id)sourceObject error:(NSError **)error
{

    NSLog(@"managedObjectContext: %@,    Source Object: %@        Error: %@", self.managedObjectContext, sourceObject, (*error).description);
    NSAssert(self.managedObjectContext, @"Unable to perform mapping: No `managedObjectContext` assigned. (Mapping response.URL = %@)", self.response.URL);
....

I noticed that the above method was called 27 (this number varies) times prior to the app crashing. In each instance, NSManagedObjectContext was present i.e. the line below:

2014-12-07 18:44:48.721 MyApp[19011:3258405] managedObjectContext:managedObjectContext: <NSManagedObjectContext: 0x1701f5800>,    Source Object: {
    friends =     (
    );
}        Error: (null)

However right before it crashed, the NSManagedObjectContext was null:

2014-12-07 18:44:53.454 MyApp[19011:3258404] managedObjectContext: (null),    Source Object: {
    friends =     (
    );
}        Error: (null)

Since the app functions normally for a while before it crashes, I'm not sure how to address this. Any pointers would be greatly appreciated.

* EDIT *

In Appdelegaate. This method is called once in viewDidLoad when the User logs in.

- (RKManagedObjectStore *)managedObjectStore
{
    if (!_managedObjectStore && [Persistence loggedIn])
    {
        NSError * error;
        NSURL * modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"App" ofType:@"momd"]];
        NSManagedObjectModel * managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
        self.managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];

        [_managedObjectStore createPersistentStoreCoordinator];

        NSArray * searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString * documentPath = [searchPaths objectAtIndex:0];

        NSString *dbName = [NSString stringWithFormat:@"%@App%@.sqlite", documentPath, [Persistence username]];
        NSPersistentStore * persistentStore = [_managedObjectStore addSQLitePersistentStoreAtPath:dbName
                                                                           fromSeedDatabaseAtPath:nil
                                                                                withConfiguration:nil
                                                                                          options:[self optionsForSqliteStore]
                                                                                            error:&error];
        NSAssert(persistentStore, @"Failed to add persistent store with error: %@", error);

        NSLog(@"Path: %@", dbName);

        if(!persistentStore)
        {
            NSLog(@"Failed to add persistent store: %@", error);
        }

        [_managedObjectStore createManagedObjectContexts];
        self.managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:self.managedObjectStore.persistentStoreManagedObjectContext];

        return self.managedObjectStore;
    }

    return _managedObjectStore;
}

- (id)optionsForSqliteStore
{
    return @{
             NSInferMappingModelAutomaticallyOption: @YES,
             NSMigratePersistentStoresAutomaticallyOption: @YES
             };
}

Creating MOC: For Core Data stack, I'm using the Default Core Data code in AppDelegate that's provided when the project is created in Xcode.

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

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _managedObjectContext;
}

MOC Operation:

- (void)saveContext
{
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
             // Replace this implementation with code to handle the error appropriately.
             // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }
}

Inside the App, the methods below are used to set, get, and clear ObjectManager:

- (void)refreshMOC
{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    self.objectManager = [self getObjectManager];

    self.objectManager.managedObjectStore = appDelegate.managedObjectStore;
    self.objectManager.managedObjectStore.managedObjectCache = appDelegate.managedObjectStore.managedObjectCache;
    self.managedObjectContext = self.objectManager.managedObjectStore.mainQueueManagedObjectContext;
}

- (RKObjectManager *)setupObjectManager
{
    NSURL *baseURL = [NSURL URLWithString:kBaseURL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc]initWithBaseURL:baseURL];
    RKObjectManager *manager = [[RKObjectManager alloc]initWithHTTPClient:httpClient];
    [manager.HTTPClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
    [manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
    [manager.HTTPClient setParameterEncoding:AFJSONParameterEncoding];
    [RKMIMETypeSerialization registeredMIMETypes];
    [RKObjectManager setSharedManager:manager];

    return [RKObjectManager sharedManager];
}

- (RKObjectManager *)getObjectManager
{
    self.objectManager = (!self.objectManager) ?  [self setupObjectManager] : self.objectManager;
    return self.objectManager;
}

- (RKObjectManager*)newObjectManager
{
    [self clearRKObjectManager];
    return [self getObjectManager];
}

- (void)clearRKObjectManager
{
    if (self.objectManager)
    {
        self.objectManager = nil;
    }
}

回答1:

Remove all of the app delegate template Core Data methods. When you use RestKit and create a managed object store you're asking RestKit to manage the Core Data stack for you so those other methods are not required (and confuse things).

When you need a MOC, get it / one from the managed object store.

Note, the above applies to saving too as you need to use the RestKit method for saving to the persistent store rather than just saving the individual MOC.