I am trying to implement an NSIncrementalStore which will access a server over an RPC API. It needs to cache all the data locally, and so I have started by creating a NSIncrementalStore to use another core data stack which is used as the cache.
So first I set up the metadata and set up the core data stack that the cache will use. The cache SQL file is the URL passed in when the store is initialised:
- (BOOL)loadMetadata:(NSError *__autoreleasing *)error {
NSMutableDictionary *mutableMetadata = [NSMutableDictionary dictionary];
[mutableMetadata setValue:[[NSProcessInfo processInfo] globallyUniqueString] forKey:NSStoreUUIDKey];
[mutableMetadata setValue:RTkCachedAPIStoreType forKey:NSStoreTypeKey];
//[mutableMetadata setValue:NSStringFromClass([self class]) forKey:NSStoreTypeKey];
[self setMetadata:mutableMetadata];
// Set up the Cache Stack
NSManagedObjectModel *model = [self.persistentStoreCoordinator.managedObjectModel copy];
self.cacheModel = model;
self.cachePersistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.cacheModel];
self.cacheContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
NSURL *storeURL;
if ([self.URL isFileURL]) {
storeURL = self.URL;
}
NSError *storeAddError = nil;
if (![self.cachePersistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:nil
error:&storeAddError]) {
NSLog(@"Fatal error while creating persistent store: %@", storeAddError);
abort();
}
[self.cacheContext setPersistentStoreCoordinator:self.cachePersistentStoreCoordinator];
return YES;
}
The execute request for a simple request for an entity look like the following code. Essentially I'm just taking the request, wrapping it up as a FetchRequest and performing the request on the Cache Core data stack. I then create the objects using the returned objectID's on the calling context:
- (id)executeRequest:(NSPersistentStoreRequest *)request withContext:(NSManagedObjectContext *)context error:(NSError *__autoreleasing *)error {
if ([request requestType] == NSFetchRequestType) {
NSFetchRequest *fetchRequest = (NSFetchRequest *)request;
NSEntityDescription *entity = [fetchRequest entity];
NSFetchRequest *cacheFetchRequest = [[NSFetchRequest alloc] init];
cacheFetchRequest.entity = entity;
__block NSArray *fetchedObjectFromCache;
[self.cacheContext performBlockAndWait:^(){
fetchedObjectFromCache = [self.cacheContext executeFetchRequest:cacheFetchRequest error:error];
}];
NSMutableArray *fetchedObjects = [NSMutableArray arrayWithCapacity:[fetchedObjectFromCache count]];
for (NSManagedObject *anObject in fetchedObjectFromCache) {
NSManagedObjectID *objectID = anObject.objectID;
NSManagedObject *managedObject = [context objectWithID:objectID];
[fetchedObjects addObject:managedObject];
}
return fetchedObjects;
}
}
When I try this out it throws an exception with the error
<unknown>:0: error: -[] : Object's persistent store is not reachable from this NSManagedObjectContext's coordinator
at the lineNSManagedObject *managedObject = [context objectWithID:objectID];
I can't work out why this is - this is the exact way that apple suggest this is done in the docs!
This error seems to be associated with accessing a context across threads - but I'm not doing that. Any suggestions as to what is wrong here?
You're using the wrong objectID.
The objectID from your cache will not match the objectID of your persistent store because your incremental store does not have the same identifier.