I want to create a entity in app A and save it into the app group shared space and access that entity in app B. This is my current approach, i'm not a master of core data so i'm sure i'm doing something wrong, the following code is for creating the entity in app A and saving it to the shared area. I receive no errors and the entity is created successfully
NSError * error = nil;
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"DataModel" withExtension:#"momd"];
NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[moc setPersistentStoreCoordinator:psc];
NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"GROUP_IDENT"];
storeURL = [storeURL URLByAppendingPathComponent:#"sharedDB.sqlite"];
NSPersistentStore *store;
store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];
Report *report = [NSEntityDescription insertNewObjectForEntityForName:#"Report" inManagedObjectContext:moc];
report.categoryID = #"THIS IS A TEST";
if ([moc save:&error] == NO) {
NSAssert(NO, #"Error saving context: %#\n%#", [error localizedDescription], [error userInfo]);
}
And then trying to access this data in the other app as follows
NSError * error = nil;
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"DataModel" withExtension:#"momd"];
NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSAssert(mom != nil, #"Error initializing Managed Object Model");
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[moc setPersistentStoreCoordinator:psc];
NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"GROUP_IDENT"];
storeURL = [storeURL URLByAppendingPathComponent:#"sharedDB.sqlite"];
NSError *error = nil;
NSPersistentStore *store = [psc persistentStoreForURL:storeURL];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Report"];
[request setEntity:[NSEntityDescription entityForName:#"Report" inManagedObjectContext:moc]];
[request setReturnsDistinctResults:YES];
NSArray * fetchedObjects = [moc executeFetchRequest:request error:&error];
store is always nil! If anyone has some suggestions or help that would be great!
You should use shared bundle:
NSBundle *sharedBundle = [NSBundle bundleWithIdentifier:#"com.company.sharedName"];
Instead of this:
[NSBundle mainBundle]
Related
I have my CoreDataManager Class and initialising Core Data Objects.
But when below piece of code runs it throws and error and cause crashing the app.
NSPersistentStoreCoordinator has no persistent stores (can't open)
When i debug the code it shows that the persistentStore object is actually nil.
Here is My CoreDataManager.m file
+ (id)sharedInstance {
static CoreDataManager *instance_ = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance_ = [[self alloc] init];
});
return instance_;
}
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext != nil) {
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [NSManagedObjectContext new];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
managedObjectModel = [[NSManagedObjectModel alloc]initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"AppTutor" withExtension:#"momd"]];
return managedObjectModel;
}
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSString *documentsStorePath =
[[[self applicationDocumentsDirectory] path] stringByAppendingPathComponent:#"AppTutor.sqlite"];
// if the expected store doesn't exist, copy the default store
if (![[NSFileManager defaultManager] fileExistsAtPath:documentsStorePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"AppTutor" ofType:#"sqlite"];
if (defaultStorePath) {
[[NSFileManager defaultManager] copyItemAtPath:defaultStorePath toPath:documentsStorePath error:NULL];
}
}
persistentStoreCoordinator =
[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// add the default store to our coordinator
NSError *error;
NSURL *defaultStoreURL = [NSURL fileURLWithPath:documentsStorePath];
NSPersistentStore *store = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:defaultStoreURL
options:nil
error:&error];
if (store == nil) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
// setup and add the user's store to our coordinator
NSURL *userStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"AppTutor.sqlite"];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:userStoreURL
options:nil
error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
return persistentStoreCoordinator;
}
Can you try to add these options to the addPersistentStoreWithType function?
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:userStoreURL
options:options
error:&error]
-(void)initCoredataWithModelName:(NSString *)modelName andDatabaseName:(NSString *)databaseName{
/** 实例化数据库 存储的 数据模型 */
NSURL * modelURL = [[NSBundle mainBundle] URLForResource:modelName withExtension:#"momd"];
NSManagedObjectModel * model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
/** 根据数据数据模型 实例化持久存储调度器 */
NSPersistentStoreCoordinator * psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
/** 指定保存的数据库文件 以及类型 */
//数据保存路径
NSString * dbPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
dbPath = [dbPath stringByAppendingPathComponent:databaseName];
NSURL * url = [NSURL fileURLWithPath:dbPath];
//保存类型
[psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:NULL];
/** 被管理对象上下文 */
_managedObjectContext = [[NSManagedObjectContext alloc] init];
//指定 存储 上下文的 持久化调度器
[_managedObjectContext setPersistentStoreCoordinator:psc];
}
-(void)saveContext{
[self.managedObjectContext save:NULL];
}
The error message is : error: Illegal attempt to save to a file that was never opened. "This NSPersistentStoreCoordinator has no persistent stores (unknown). It cannot perform a save operation.". No last error recorded.
Can anyone please tell me, how to migrate local store to icloud, when using Magic record. Will magic record has any support for that. Is there any documentation for magic Record.
I am struggling from three days.
NSURL *documentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *storeURL = [documentsDirectory URLByAppendingPathComponent:#"ABC.sqlite"];
NSManagedObjectModel *model = [NSManagedObjectModel MR_defaultManagedObjectModel];
NSPersistentStoreCoordinator *coord = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSURL *seedStoreURL = [documentsDirectory URLByAppendingPathComponent:#"ABCCloud"];
NSError *seedStoreError;
NSDictionary *seedStoreOptions = #{NSReadOnlyPersistentStoreOption: #YES};
NSPersistentStore *seedStore = [coord addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:seedStoreURL options:seedStoreOptions error:&seedStoreError];
NSDictionary *iCloudOptions =
#{NSPersistentStoreUbiquitousContentNameKey: #"CloudStore"};
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSError *error = nil;
NSPersistentStore *iCloudStore = [coord migratePersistentStore:seedStore
toURL:storeURL
options:iCloudOptions
withType:NSSQLiteStoreType
error:&error];
Sorry I removed magical record code now. This is the code i write for migration, but persistent store is nil..
This is the error
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'nil is not a valid persistent
store'
This is the current initialisation code in my app, based on cs193p by Paul Hegarty:
UIManagedDocument *database = nil;
if (!database) {
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:#"stdDatabase"];
database = [[UIManagedDocument alloc] initWithFileURL:url];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
database.persistentStoreOptions = options;
}
if (![[NSFileManager defaultManager] fileExistsAtPath:[database.fileURL path]]){
[database saveToURL:database.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){
completionBlock(database);
}];
} else if (database.documentState == UIDocumentStateClosed){
[database openWithCompletionHandler:^(BOOL success){
completionBlock(database);
}];
} else if (database.documentState == UIDocumentStateNormal) {
completionBlock(database);
}
This is the new initialisation code I want to use, based on the "Core Data" book by Marcus Zarra:
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Corrida_de_Leitos" withExtension:#"momd"];
ZAssert(modelURL, #"Failed to find model URL");
NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
ZAssert(mom, #"Failed to initialize model");
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
ZAssert(psc, #"Failed to initialize persistent store coordinator");
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[moc setPersistentStoreCoordinator:psc];
[self setManagedObjectContext:moc];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *storeURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
storeURL = [storeURL URLByAppendingPathComponent:#"stdDatabase"];
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setValue:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setValue:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
NSError *error = nil;
NSPersistentStoreCoordinator *coordinator = [moc persistentStoreCoordinator];
NSPersistentStore *store = [coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];
if (!store) {
NSLog(#"Error adding persistent store to coordinator %#\nUSERINFO:\n%#", [error localizedDescription], [error userInfo]);
}
dispatch_sync(dispatch_get_main_queue(), ^{
[self contextInitialized];
});
});
This is the error I get when adding the store to the coordinator:
'Error adding persistent store to coordinator The operation couldn’t be completed. (Cocoa error 256.)
USERINFO:
{
NSSQLiteErrorDomain = 14;
NSUnderlyingException = "unable to open database file";
}'
How do I fix the new code so it is able to open the old database file?
The UIManagedDocument will have created this sqlite file inside the UIManagedDocument package (a directory) so you need to get the URL to the original sqlite file and use this as the URL in the new version of the app, if necessary use the NSFileManager to move the file to another location, but that's not really necessary. See example directory structure from UIManagedDocument, one for local and one for iCloud synced store. If its not iOS7 then check because the structure/names may be different.
In theory you can get the actual store file name from UIManagedDocument.persistentStoreName and simply append that to UIManagedDocument.fileURL - but in practice this omits the StoreContent subdirectory I think.
Usually UIManagedDocument would have created the file at "stdDatabase/StoreContent/persistentStore". But to be sure run the original version of the app in the simulator and then check exactly what path is used to create the store file.
The actual sqlite file should work fine as long as you open using the same options.
The problem is that UIManagedDocument creates the stack for you and saves your database file with a format not compatible with a SQLite file, if you want to use a SQLite file you first have to migrate the store (file), the NSPersistentStoreCoordinator have a method called migratePersistentStore:toURL:options:withType:error: which can do this migration.
When I update my app, I'm doing some stuff with my CoreData model on startup and afterwards I replace the .sqlite file the persistent store uses with:
NSArray *stores = [__persistentStoreCoordinator persistentStores];
for(NSPersistentStore *store in stores) {
[__persistentStoreCoordinator removePersistentStore:store error:nil];
[[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:nil];
}
__persistentStoreCoordinator = nil;
[self persistentStoreCoordinator];
__managedObjectContext = nil;
[self managedObjectContext];
Everything works fine, just the way it is suposed to. But when I close the app via the homebutton, it crashes:
[NSPersistentStoreCoordinator retain]: message sent to deallocated instance
I'm using ARC ... actually you could say it doesn't matter, because it crashes when being closed, so you don't notice the crash. But, of course, that's not an option and there has to be a right way to do that!?
Any ideas? Why is there a retain sent to the NSPersistenStoreCoordinator? It has something to do with __persistentStoreCoordinator = nil; but I need to nil it, otherwise it doesn't use the new .sqlite.
Cheers!
Well finaly I found a better (and working) way to replace the .sqlite & storeCoordinator's store, without the need to nil the persistentStoreCoordinator:
NSArray *stores = [__persistentStoreCoordinator persistentStores];
for(NSPersistentStore *store in stores) {
[__persistentStoreCoordinator removePersistentStore:store error:nil];
[[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:nil];
}
NSString *storePath = [[self applicationDocumentsDirectoryString] stringByAppendingPathComponent:#"PictureApp.sqlite"];
NSURL *storeUrl = [NSURL fileURLWithPath:[[self applicationDocumentsDirectoryString] stringByAppendingPathComponent:#"PictureApp.sqlite"]];
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"PictureApp" ofType:#"sqlite"];
if (defaultStorePath) {
[[NSFileManager defaultManager] copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
NSError *error = nil;
[__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error];