I have an existing app (available in appStore) that I want to reboot from scratch, and make it as an update. So I started a new project and reproduce all as equal (name, bundleId, xcdatamodel etc) like in the old project.
I want to test if data are well saved when I update the old app with the new one, but when I build it, I get this error from xcode "application Permission denied".
I read that this error is due to the fact that I try to install an application with the same bundleId that already present on the device. I do not understand because I'm trying to simulate an update.
What can I do to get this working ?
Ok, here is the solution that helps me.
Build an archive an install it using iTunes instead of xcode direct build.
The other problem was, the first version of the app was built for the first iPad when xcode was available, but the devices were not yet sold. Here is the old -(NSPersistentStoreCoordinator *)persistentStoreCoordinator method used :
-(NSPersistentStoreCoordinator *)storeCoorditator{
if(storeCoorditator){
return storeCoorditator;
}
storeCoorditator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self objectModel]];
NSError *lc_error = nil;
NSString *lc_path = [NSString stringWithFormat:#"%#/data.sqlite",[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]];
NSURL *storeUrl = [NSURL fileURLWithPath:lc_path];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
[storeCoorditator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&lc_error];
return storeCoorditator;
}
And here is the method I tried to use :
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeUrl = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"PDF.sqlite"];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
As the storeUrl wasn't the same, the data couldn't be found ;)
Now everything's fine, I can get my data back !
Related
I have used cord data in my application, its already uploaded and live on app store. Now I want to upload a new version with some changes in core data but application is crashing with following error -
reason = "Can't find model for source store";
My code is already having atomic migration here is the code
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
if(![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeUrl options:options error:&error])
I read the apple documentation and try to use
- (BOOL)migrateStore:(NSURL *)storeURL toVersionTwoStore:(NSURL *)dstStoreURL error:(NSError **)outError
But how I find destination and source StoreURL here? From where should I call this method? And how?
Please give some suggestions to solve this problem.
I have solved this problem with the help of this tutorial.
http://code.tutsplus.com/tutorials/core-data-from-scratch-migrations--cms-21844
Worth reading... :) Enjoy
in my app i have to store core data database. And i have some groups and folders with default data (audiofiles, maptiles, etc) in the xcode project navigator.
I found a lot about preventing files from being backed up like:
What i have done:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"db.sqlite"];
NSLog(#"%#", storeURL.path);
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
//NSDictionary *options = #{NSMigratePersistentStoresAutomaticallyOption:#YES, NSInferMappingModelAutomaticallyOption:#YES};
/*NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];*/
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[self addSkipBackupAttributeToItemAtURL:storeURL];
return _persistentStoreCoordinator;
}
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
preventing method:
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(#"Error excluding %# from backup %#", [URL lastPathComponent], error);
}
return success;
}
(The minimum target iOS version is 7.0)
Is this enough? How can i check if the app now prevent backing up the core data database?
Before i added the addSkipBackupAttributeToItemAtURL method i checked the apps storage and found nothing under documents and data. I only found 3.1 MB under backups -> my iphone
- Install and launch your app
- Go to Settings > iCloud > Storage & Backup > Manage Storage
- If necessary, tap "Show all apps"
- Check your app's storage
You are doing it right.
Following the Apple Technical Q&A 1719: How do I prevent files from being backed up to iCloud and iTunes? you should mark with the "do not back up" attribute.
For NSURL objects, add the NSURLIsExcludedFromBackupKey attribute to prevent the corresponding file from being backed up. For CFURLRef objects, use the corresponding kCFURLIsExcludedFromBackupKey attribute.
To know which folder is more appropriated to store you Core Data database you can check the iOS Data Storage Guidelines.
I am trying to migrate my current core data structure to a new data structure however I am continually getting the same error no matter what I do:
Terminating app due to uncaught exception 'Open Failed', reason: 'Reason: The operation couldn’t be completed. (Cocoa error 134100.)'
According to the documentation this means: NSPersistentStoreIncompatibleVersionHashError
I cannot just erase the app from the simulator as it has already gone out to the app store.
The persistent store coordinator in the app delegate is as follows:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"DATABASELOC.sqlite"];
NSLog(#"URL: %#", storeURL);
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator;
}
And my managedobjectmodel within the app delegate is as follows:
- (NSManagedObjectModel *)managedObjectModel
{
if (managedObjectModel != nil) {
return managedObjectModel;
}
NSString *path = [[NSBundle mainBundle] pathForResource:#"DATABASELOC" ofType:#"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];
return managedObjectModel;
}
I have generated a second model version, and updated the current version, and if I choose either as the current, if it is the same as the original model it loads fine. However as soon as I make a minor change the model that is current the same error comes up.
I guess it appears that it is not recognizing that there is a new model, but no matter what I do I cannot get past this error.
Has anyone else had this problem? Can anyone offer some advice?
Let me know if you need any more information.
Thanks in advance for your help!
Short question:
I want to run a certain code in my app only if my Core Data model has changed (new entities, new properties, etc). How can I determine if the model has changed or not?
Just some pseudo-code:
if (current_model_version != previous_model_version) {
//do some code
} else {
// do some other code
}
I'm guessing I might use versionHashes to do this, or isConfiguration:compatibleWithStoreMetadata:, but I'm not certain how.
Some editing for clarity: 'current' as in 'now' and 'previous' as in 'last time app was launched.'
The answer seems to be isConfiguration:compatibleWithStoreMedia:.
I found some useful information here:
http://mipostel.com/index.php/home/70-core-data-migration-standard-migration-part-2
I set it up this way:
- (BOOL)modelChanged
{
NSError *error;
NSURL * sourceURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"db.sqlite"];
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:sourceURL error:&error];
BOOL isCompatible = [[self managedObjectModel] isConfiguration:nil compatibleWithStoreMetadata:sourceMetadata];
return isCompatible;
}
'self' is my shared data store, not that it necessarily has to go there.
deanWombourne points out that what this really does is determine whether or not the data can be automatically migrated, so it's not exactly the solution to the problem I posed. It does serve my needs in this case.
This is replacement code for - (NSPersistentStoreCoordinator *)persistentStoreCoordinator that you get if you tick the Core Data box when setting up a new project in XCode.
It attempts to open the existing sqlite file (using lightweight migration if necessary). If that fails, it deletes and re-creates the store.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSError *error = nil;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL options:options error:&error])
{
NSLog(#"Couldn't open the store. error %#, %#", error, [error userInfo]);
[self deleteSqliteFilesForStore:self.storeURL];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
// or [NSException raise ...]
}
else
{
NSLog(#"Store deleted and recreated");
// TEST DATA RE-INITIALIZATION CODE GOES HERE
}
}
else
{
NSLog(#"Existing Store opened successfully");
}
return _persistentStoreCoordinator;
}
- (void)deleteSqliteFilesForStore:(NSURL *)storeURL
{
NSURL *baseURL = [storeURL URLByDeletingPathExtension];
// Delete the associated files as well as the sqlite file
for (NSString *pathExtension in #[#"sqlite",#"sqlite-shm",#"sqlite-wal"])
{
NSURL *componentURL = [baseURL URLByAppendingPathExtension:pathExtension];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[componentURL path]];
if(fileExists)
{
[[NSFileManager defaultManager] removeItemAtPath:[componentURL path] error:nil];
}
}
}
I'm using Core Data in an existing application. Now I want to integrate iCloud so that the user can synchronize their contents between their iOS-devices. To do that I've written the following code for my NSPersistentStoreCoordinator (of course the placeholders are filled out in my code):
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"<DB_Name>.sqlite"];
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSPersistentStoreCoordinator* psc = persistentStoreCoordinator_;
if (IOS_VERSION_GREATER_THAN_OR_EQUAL_TO(#"5.0")) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSFileManager *fileManager = [NSFileManager defaultManager];
// Migrate datamodel
NSDictionary *options = nil;
// this needs to match the entitlements and provisioning profile
NSURL *cloudURL = [fileManager URLForUbiquityContainerIdentifier:#"<App_Identifier>"];
NSString* coreDataCloudContent = [[cloudURL path] stringByAppendingPathComponent:#"data"];
if ([coreDataCloudContent length] != 0) {
// iCloud is available
cloudURL = [NSURL fileURLWithPath:coreDataCloudContent];
options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
#"<App_Name>.store", NSPersistentStoreUbiquitousContentNameKey,
cloudURL, NSPersistentStoreUbiquitousContentURLKey,
nil];
} else {
// iCloud is not available
options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
}
NSError *error = nil;
[psc lock];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
[psc unlock];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"asynchronously added persistent store!");
[[NSNotificationCenter defaultCenter] postNotificationName:#"RefetchAllDatabaseData" object:self userInfo:nil];
});
});
} else {
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
NSError *error = nil;
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}
return persistentStoreCoordinator_;
}
With that code all new added data records are synchronized automatically between all iOS-devices, so that works exactly the way it should!
But what I want is that also all the existing data records are synced between all devices; that doesn't work yet. The existing records are still available within the app and can be used, but they are not synchronized.
What do I need to do to get all the existing data records synced with iCloud too? I've experimented a bit with the method
migratePersistentStore:toURL:options:withType:error:
but without any success.
I'm very grateful for any help!
Look up the WWDC 2012 session Using CoreData with iCloud. They discuss this during the final section, under the topic of seeding. They also have some sample code that you can get from the site that has an example. In short, you will have to open 2 persistent stores, set a fetch size, then grab batches from the source, loop through them and add them to the new store, and at batch size intervals, save and reset. Pretty simple.