Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
443 views
in Technique[技术] by (71.8m points)

ios - RestKit: 'NSInternalInconsistencyException', reason: 'Unable to perform mapping: No `managedObjectContext` assigned

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;
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...