I follow this nice tutorial http://mipostel.com/index.php/home/70-core-data-migration-standard-migration-part-2 to do my core data migration.
For some strange reason i always get NULL in the mappingModel in these lines:
NSMappingModel *mappingModel = [NSMappingModel mappingModelFromBundles:nil
forSourceModel:sourceModel
destinationModel:destinationModel];
(line 191 in the linked code)
I tried to create a very simple derived version of the model, I recreated a mappingModel a 1000 times, made sure that the mapping model file is in the project directory - but this call always returns NULL.
Anybody has an idea what is wrong here?
ps I was just wondering that setting the migration options is called AFTER the mapping Model is used.
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSError *error;
NSDictionary *pscOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:NO], NSInferMappingModelAutomaticallyOption,
nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeUrl
options:pscOptions
error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
(lines 123...)
Anyway
Why can't the mapping model be found ?
pss couldn't help holding back :-) this core data migration stuff is much too complicated and difficult compared to doing simple SQL DB migration - wasting soooo much time.
So a BIG THANKS in advance!
I followed that same tutorial and ended up having to manualy open my mapping model by URL
NSString *mappingModelPath = [[NSBundle mainBundle] pathForResource:#"mappingModel10" ofType:#"cdm"];
NSLog(#"mapping model path:%#", mappingModelPath);
NSURL *mappingModelUrl = [NSURL fileURLWithPath:mappingModelPath];
NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:mappingModelUrl];
I found the file name for my mapping model by looking in my App's bundle.
Related
I have a pretty weird problem. I'm using coredata to save notes. I can access/save/edit all the attributes of the "Notes" entity, besides one : category.
-(void)editCategory {
NSFetchRequest *request = [[NSFetchRequest alloc]init];
NSEntityDescription *categRequest = [NSEntityDescription entityForName:#"Notes" inManagedObjectContext:_managedObjectContext];
request.predicate = [NSPredicate predicateWithFormat:#"text = %#", noteToEdit];
[request setEntity:categRequest];
//Error handling
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[_managedObjectContext executeFetchRequest:request error:&error]mutableCopy];
if (mutableFetchResults == nil) {
NSLog(#"Error happened : %#", error);
}
Notes *editMe = [mutableFetchResults objectAtIndex:0];
[editMe setCategory:editCategoryText];
NSLog(#"Category from pickerview : %#", editCategoryText);
if (![_managedObjectContext save:&error]) {
NSLog(#"couldnt save : %#", error);
}
}
This line :
[editMe setCategory:editCategoryText];
is crashing. editCategoryText is a string, as the category attribute. The weird thing is that I'm using the exact same piece of code to change the title attribute, and I don't have any problem.
Log file :
2013-11-07 15:49:20.286 Simple Notes 1[16511:a0b] -[__NSCFString managedObjectContext]: unrecognized selector sent to instance 0x8dccc30
2013-11-07 15:49:20.293 Simple Notes 1[16511:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString managedObjectContext]: unrecognized selector sent to instance 0x8dccc30'
Do you have any idea why this attribute is behaving differently from the others ? Thank you.
Not at a computer so can't test this but:
Get rid of the mutableCopy. executeFetchRequest returns autoreleased objects, which you are then trying to copy, this turns into a garbage pointer, which happens to end up pointing to a string.
Actually it seems like it was a core data bug, I solved it by deleting my app in the simulator, deleting the core data model in xcode, built it again and performed a clean.
I have a memory problem in an iPhone app, giving me a hard time.
Here is the error message I get:
malloc: * mmap(size=9281536) failed (error code=12)
* error: can't allocate region
I am using ARC for this app, in case that might be useful information.
The code (below) is just using a file in the Bundle in order to load a core data entity.
The strange thing is the crash happens only after more than 90 loops;
while it seems to mee that since the size of the "contents" in getting smaller and smaller, the memory request should also get smaller and smaller.
Here is the code, if any one can see a flaw please let me know.
NSString *path,*contents,*lineBuffer;
path=[[NSBundle mainBundle] pathForResource:#"myFileName" ofType:#"txt"];
contents=[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
int counter=0;
while (counter<10000) {
lineBuffer=[contents substringToIndex:[contents rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]].location];
contents=[contents substringFromIndex:[lineBuffer length]+1];
newItem=[NSEntityDescription insertNewObjectForEntityForName:#"myEntityName"
inManagedObjectContext:context];
[newItem setValue:lineBuffer forKey:#"name"];
request=[[NSFetchRequest alloc] init];
[request setEntity: [NSEntityDescription entityForName:#"myEntityName"
inManagedObjectContext:context]];
error=nil;
[context save:&error];
counter++;
}
I finally solved the problem using NSMutableString instead of NSString for contents.
And then using : [contents deleteCharactersInRange:range];
maintaining range adequately of course.
inside the loop.
i'm having a very hard issue to solve. I've got this scenario:
My app uses CoreData to storing objects, I want to implement iCloud sync between devices... and my app requires an initial populated database.
The first time I launch my app, it's going to populate my database on the cloud and marks to YES some db'fields as "databaseInstalled". These fields are synced in the cloud too.
Now when another device launch the app for the first time, I was hoping to retrieve the field "databaseInstalled" to check whether inject or not some data but it's wrong...
If databaseInstalled is false, we inject data, if databaseInstalled it's true, we wait for iCloud sync.
The problem is that I retrieve the persistentStoreCoordinator asynchronically because of I don't want to block the app that is waiting to download data from iCloud...
So how can I know a priori if i need to populate the database or it has been filled on another device and I've just to download from iCloud the populated one?
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if((__persistentStoreCoordinator != nil)) {
return __persistentStoreCoordinator;
}
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator;
// Set up iCloud in another thread:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// ** Note: if you adapt this code for your own use, you MUST change this variable:
NSString *iCloudEnabledAppID = #"this is a secret!";
// ** Note: if you adapt this code for your own use, you should change this variable:
NSString *dataFileName = #"you do not have to know.sqlite";
// ** Note: For basic usage you shouldn't need to change anything else
NSString *iCloudDataDirectoryName = #"Data.nosync";
NSString *iCloudLogsDirectoryName = #"Logs";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];
if (iCloud) {
NSLog(#"iCloud is working");
NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];
NSLog(#"iCloudEnabledAppID = %#",iCloudEnabledAppID);
NSLog(#"dataFileName = %#", dataFileName);
NSLog(#"iCloudDataDirectoryName = %#", iCloudDataDirectoryName);
NSLog(#"iCloudLogsDirectoryName = %#", iCloudLogsDirectoryName);
NSLog(#"iCloud = %#", iCloud);
NSLog(#"iCloudLogsPath = %#", iCloudLogsPath);
// da rimuovere
//[fileManager removeItemAtURL:iCloudLogsPath error:nil];
#warning to remove
if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
NSError *fileSystemError;
[fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]
withIntermediateDirectories:YES
attributes:nil
error:&fileSystemError];
if(fileSystemError != nil) {
NSLog(#"Error creating database directory %#", fileSystemError);
}
}
NSString *iCloudData = [[[iCloud path]
stringByAppendingPathComponent:iCloudDataDirectoryName]
stringByAppendingPathComponent:dataFileName];
//[fileManager removeItemAtPath:iCloudData error:nil];
#warning to remove
NSLog(#"iCloudData = %#", iCloudData);
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[options setObject:iCloudEnabledAppID forKey:NSPersistentStoreUbiquitousContentNameKey];
[options setObject:iCloudLogsPath forKey:NSPersistentStoreUbiquitousContentURLKey];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:[NSURL fileURLWithPath:iCloudData]
options:options
error:nil];
[psc unlock];
}
else {
NSLog(#"iCloud is NOT working - using a local store");
NSLog(#"Local store: %#", localStore.path);
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:localStore
options:options
error:nil];
[psc unlock];
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"iCloud routine completed.");
Setup *install = [[Setup alloc] init];
if([install shouldMigrate]) {
HUD = [[MBProgressHUD alloc] initWithView:self.window.rootViewController.view];
HUD.delegate = self;
HUD.labelText = NSLocalizedString(#"Sincronizzazione del database", nil);
[self.window.rootViewController.view addSubview:HUD];
[HUD showWhileExecuting:#selector(installDatabase) onTarget:install withObject:nil animated:YES];
}
else {
[[NSNotificationCenter defaultCenter] postNotificationName:#"setupCompleted" object:self];
}
//[[NSNotificationCenter defaultCenter] postNotificationName:#"icloudCompleted" object:self userInfo:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"setupCompleted" object:self];
});
});
return __persistentStoreCoordinator;
}
You can't know whether or not there's going to be data available in iCloud until you finish syncing with iCloud. That means that you've got two options:
Make the user wait until the sync is done.
Start up with your default database and merge changes from iCloud when possible.
With iCloud, you need some strategy for resolving conflicts between local data and cloud data because you have to deal with the fact that users might change data on more than one device at the same time. Once you have that in place, it seems pretty clear that the second option above is the better one: users get to start using your app right away, and data from the cloud is merged when it's available.
I had exactly same problem.
Check out my question & my answer to it iCloud + CoreData - how to avoid pre-filled data duplication?
Actually it doesn't work 100% ok. If you dare to try it I can explain you how you might make it work 100% correctly (I haven't tried yet, though).
Taking into account that you have a lot of data to pre-populate my solution might now work out for you.
There is no way to determine whether a data store is being opened for the first time. At least not on iCloud Core Data store. Think of it, iCloud should also work off-line – that is, all changes should be buffered when the user is disconnected from the Internet and then uploaded when the connection is restored. There is no way to check whether a data store was initialized without potentially making the user wait for a few minutes (or even indefinitely if the device is off-line) to ask iCloud's copy of the data sore.
To solve this, you'll need to follow these four simple guidelines:
Have a way to de-duplicate pre-populated records.
Have a way to identify pre-populated records and differentiate it from user-entered ones.
Run the de-duplication process every time new transaction records came in from iCloud.
Only seed data records once per device/account combination.
You can read more details here: http://cutecoder.org/programming/seeding-icloud-core-data/
I have a one to many relationship in my core data model. I need to create a new entity and save it. The entity has a one to many relationship which generated the following code:
- (void)addRelationshipEvent1:(NSSet *)values;
- (void)removeRelationshipEvent1:(NSSet *)values;
.
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
ApplicationRecord *newManagedObject = (ApplicationRecord*)[NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
newManagedObject.startDate = [NSDate date];
newManagedObject.stopDate = [[NSDate date] dateByAddingTimeInterval:120];
//keep adding individual dynamic properties
is it correct to set the -toMany relationship sets to nil initially? Or do I need to initialize an (empty?) set here and assign it? Would I be able to add extra objects later if I set the initial set to nil?
newManagedObject.relationshipEvent1 = nil;
newManagedObject.relationshipEvent2 = nil;
//...
// Save the context.
NSError *error = nil;
if (![context 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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
Alex,
You don't need to intialize your relationships. Just use the supplied accessors or helper functions and Core Data takes care of it. IOW, only worry about the property/relationship when you need to actually use it.
Andrew
I am writing an application, which stores a huge number of very short strings (mostly one to three unicode chars) and lots of relationships. This results in a massive overhead for storing the relationships in the XML format and even more so in the Binary format (which is strange). So if I use XML or Binary, i get huge files and very long save and load times.
The SQLite format is more compact and saves faster (especially in case of small changes), but for some reason the queries using predicates with format "$something BEGINSWITH[c] fieldInMyObject" do not work, and i can't do without them.
Is there anything i can do to reduce the volume of the files and speed up loading and saving (apart from using SQLite directly)?
Best regards,
Timofey.
UPD
Here is the code for saving the data:
‐ (IBAction) saveAction:(id)sender {
NSError *error = nil;
if (![[self managedObjectContext] commitEditing]) {
NSLog(#"%#:%s unable to commit editing before saving", [self class], _cmd);
}
if (![[self managedObjectContext] save:&error]) {
[[NSApplication sharedApplication] presentError:error];
}
}
And here is the code for loading data (both for creating new files and loading existing ones):
- (void) panelReturnedURL:(NSURL *)url {
NSManagedObjectModel *mom = [self managedObjectModel];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:mom];
NSError *error = nil;
if (![persistentStoreCoordinator addPersistentStoreWithType: NSBinaryStoreType
configuration:nil
URL:url
options:nil
error:&error]) {
[NSApp presentError:error];
}
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: persistentStoreCoordinator];
[mainWinController window];
}
And i don't don't save when objects are modified, the context is saved when the application quits or when the user explicitly saves it.
XML and binary can be slow for large files because they have to be read entirely into memory in one chunk in order to work. If you have a lot of data your really need to use an SQLite store.
Your problems with the predicate having nothing to do with the SQLite store. That type of predicate is used routinely. I would suggest posting a seperate question with a layout of your entities and the predicate you want to use: