UIAlertView does not show up from the Appdelegate - core-data

I am working on core data migration. I am trying to handle exception when the persistent stores do not match and the app crashes. But before it crashes, i would like to let the user know (through an alert view) that he needs to uninstall the app first, and the re-install it. I have the code for the alert view in persistentStoreCoordinator accessor method, but the alertview never shows up.
Here is the code:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"ExchangeMail.sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// Dictionary required to store the details of psc on the disk,
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeURL error:&error];
// This BOOL value is required to check whether a migration is required or not.
BOOL pscCompatibile = [[self managedObjectModel] isConfiguration:nil compatibleWithStoreMetadata:sourceMetadata];
NSLog(#"Migration needed? %d", !pscCompatibile);
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
[options setValue:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setValue:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Non-matching Database File" message:#"The model configuration used to open the store is compatible with the one that was used to create the store. Please Uninstall the App and try again." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[__persistentStoreCoordinator lock];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
// dispatch_queue_t queue = NULL;
// queue = dispatch_get_main_queue();
// dispatch_async(queue, ^{
// [[NSFileManager defaultManager]removeItemAtURL:storeURL error:nil];
//
// [self.myAlertView show];
// });
[self.myAlertView show];
//exit(-1);
}
[__persistentStoreCoordinator unlock];
if(!pscCompatibile){
isMigrationRequired = YES;
}
return __persistentStoreCoordinator;
}

Related

RestKit and Collapsible Menu, synchronize with Core Data

I'm using RestKit and RRNCollapsableTable. The problem is, when I load view for the first time, RestKit is downloading data from JSON. That delay causes menu to not load. What I'm trying to do is to make CollapsableTable wait for data.
[self requestData:^(BOOL success) {
if (success) {
_menu = [self buildMenu];
[self model];
}
}];
- (void)requestData:(void (^)(BOOL success))completionBlock {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Messages"];
NSSortDescriptor *byId = [NSSortDescriptor sortDescriptorWithKey:#"customNewsId" ascending:YES];
fetchRequest.sortDescriptors = #[byId];
NSError *error = nil;
// Setup fetched results
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext
sectionNameKeyPath:#"customNewsId"
cacheName:nil];
//[self.fetchedResultsController setDelegate:self];
BOOL fetchSuccessful = [self.fetchedResultsController performFetch:&error];
if (!fetchSuccessful) {
abort();
}
[[RKObjectManager sharedManager] getObjectsAtPath:#"api/json/get/bZmroLaBCG" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
RKLogInfo(#"Load complete: Table should refresh...");
//[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:#"LastUpdatedAt"];
//[[NSUserDefaults standardUserDefaults] synchronize];
NSError *error = nil;
if ([[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext hasChanges] && ![[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext saveToPersistentStore:&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();
}
completionBlock(YES);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"Load failed with error: %#", error);
completionBlock(NO);
}];
completionBlock(YES);
}
Then BuildMenu is just iterating over fetched objects and put them in section.
-(NSArray *)buildMenu {
__block NSMutableArray *collector = [NSMutableArray new];
NSInteger sections = [self.fetchedResultsController.sections count];
for (NSInteger i = 0; i < sections; i++) {
Messages *message = [_fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:i]];
MenuSection *section = [MenuSection new];
section.items = #[message.message,message.pushNotificationMessage];
section.title = message.title;
NSLog(#"section.title - %#",section.title);
[collector addObject:section];
}
return [collector copy];
}
Method model is responsible for DataSource for CollapsableTable.
-(NSArray *)model {
return _menu;
}
Thanks in advance for any help.
Greetings.

Core Data properties based upon relationships returning NULL

I have a Core Data data model such as
I want to display the Teams.name associated with each Batting object in my UITableViewCell. When I try to access batting.teams.name it returns NULL.
My opening view controller has a string passed in then creates a new viewController with NSPredicate based from Master.nameLast and lists all names matching
and the NSFetchedResultsController which created the above list
#pragma mark - Fetched Results Controller Section
- (NSFetchedResultsController *)fetchedResultsController {
if(_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [self managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Master" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"debut" ascending:YES];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"nameLast = [c]%#", lastName];
[fetchRequest setPredicate:predicate];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
fetchRequest.sortDescriptors = sortDescriptors;
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
return _fetchedResultsController;
}
My next view controller then lists all Batting properties associated with the selected Master NSManagedObject.
But when I try to access batting.teams.name it returns NULL!!!!! If I NSLog the entity from my delegate they are set but I can't access Teams.name from it's Batting.teams relationship
#pragma mark - Fetched Results Controller Section
- (NSFetchedResultsController *)fetchedResultsController {
if(_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [self managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Batting" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"yearID" ascending:YES];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"playerID = %# " , selectedMaster.playerID];
[fetchRequest setPredicate:predicate];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
fetchRequest.sortDescriptors = sortDescriptors;
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
return _fetchedResultsController;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"playerStats" forIndexPath:indexPath];
Batting *batting = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *team = batting.teams.name; //NULL NULL NULL
// Configure the cell...
double average = [batting.h doubleValue]/[batting.ab doubleValue];
NSString *averageStr = [[NSString stringWithFormat:#"%.3f", average] substringFromIndex:1];
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", batting.yearID, batting.teams.name];
cell.detailTextLabel.text = [NSString stringWithFormat:#"H: %#, AVG: %#, HR: %#, RBI: %#, SB: %#, R: %#, BB: %#, K: %#",
batting.h, averageStr , batting.hr, batting.rbi, batting.sb, batting.r, batting.bb, batting.so];
cell.detailTextLabel.textColor = [UIColor grayColor];
return cell;
}
returns null for the second argument????????
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", batting.yearID, batting.teams.name];
and this is the Teams entity logged from the AppDelegate
//
// AppDelegate.m
// Baseball Stats
//
// Created by Jason Steindorf on 6/6/15.
// Copyright (c) 2015 Jason Steindorf. All rights reserved.
//
#import "AppDelegate.h"
#import "Master.h"
#import "Teams.h"
#import "Batting.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
NSError *error;
NSString* dataPath_MASTER = [[NSBundle mainBundle] pathForResource:#"master" ofType:#"json"];
NSArray* MASTER = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_MASTER]
options:kNilOptions
error:&error];
NSString* dataPath_TEAMS = [[NSBundle mainBundle] pathForResource:#"teams" ofType:#"json"];
NSArray* TEAMS = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_TEAMS]
options:kNilOptions
error:&error];
NSString* dataPath_ABC = [[NSBundle mainBundle] pathForResource:#"abc" ofType:#"json"];
NSArray* BATTING_ABC = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_ABC]
options:kNilOptions
error:&error];
NSString* dataPath_DEFGH = [[NSBundle mainBundle] pathForResource:#"defgh" ofType:#"json"];
NSArray* BATTING_DEFGH = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_DEFGH]
options:kNilOptions
error:&error];
NSString* dataPath_IJKLM = [[NSBundle mainBundle] pathForResource:#"ijklm" ofType:#"json"];
NSArray* BATTING_IJKLM = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_IJKLM]
options:kNilOptions
error:&error];
NSString* dataPath_NOPQR = [[NSBundle mainBundle] pathForResource:#"nopqr" ofType:#"json"];
NSArray* BATTING_NOPQR = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_NOPQR]
options:kNilOptions
error:&error];
NSString* dataPath_ST = [[NSBundle mainBundle] pathForResource:#"st" ofType:#"json"];
NSArray* BATTING_ST = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_ST]
options:kNilOptions
error:&error];
NSString* dataPath_UVWXYZ = [[NSBundle mainBundle] pathForResource:#"uvwxyz" ofType:#"json"];
NSArray* BATTING_UVWXYZ = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_UVWXYZ]
options:kNilOptions
error:&error];
// Test listing all Master from the store
NSFetchRequest *fetchRequestMaster = [[NSFetchRequest alloc] init];
NSEntityDescription *entityMaster = [NSEntityDescription entityForName:#"Master" inManagedObjectContext:self.managedObjectContext];
[fetchRequestMaster setEntity:entityMaster];
NSArray *fetchedObjectsMaster = [self.managedObjectContext executeFetchRequest:fetchRequestMaster error:&error];
NSLog(#"Number of records in master.json - %d", (int)[fetchedObjectsMaster count]);
for (id m in MASTER) {
Master *master = [NSEntityDescription insertNewObjectForEntityForName:#"Master"
inManagedObjectContext:self.managedObjectContext];
master.nameFirst = [m objectForKey:#"nameFirst"];
master.nameLast = [m objectForKey:#"nameLast"];
master.debut = [m objectForKey:#"debut"];
master.playerID = [m objectForKey:#"playerID"];
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
fetchedObjectsMaster = [self.managedObjectContext executeFetchRequest:fetchRequestMaster error:&error];
for (Master *master in fetchedObjectsMaster) {
NSLog(#"first name: %#", master.nameFirst);
NSLog(#"last name: %#", master.nameLast);
NSLog(#"debut: %#", master.debut);
NSLog(#"playerID: %#\n\n", master.playerID);
}
// Test listing all Master from the store
NSFetchRequest *fetchRequestTeams = [[NSFetchRequest alloc] init];
NSEntityDescription *entityTeams = [NSEntityDescription entityForName:#"Teams" inManagedObjectContext:self.managedObjectContext];
[fetchRequestTeams setEntity:entityTeams];
NSArray *fetchedObjectsTeams = [self.managedObjectContext executeFetchRequest:fetchRequestTeams error:&error];
NSLog(#"Number of records in teams.json - %d", (int)[fetchedObjectsTeams count]);
for (id t in TEAMS) {
Teams *team = [NSEntityDescription insertNewObjectForEntityForName:#"Teams"
inManagedObjectContext:self.managedObjectContext];
team.name = [t objectForKey:#"name"];
team.minYearID = [t objectForKey:#"minYearID"];
team.maxYearID = [t objectForKey:#"maxYearID"];
team.teamID = [t objectForKey:#"teamID"];
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
fetchedObjectsTeams = [self.managedObjectContext executeFetchRequest:fetchRequestTeams error:&error];
for (Teams *team in fetchedObjectsTeams) {
NSLog(#"name: %#", team.name);
NSLog(#"minYearID: %#", team.minYearID);
NSLog(#"maxYearID: %#", team.maxYearID);
NSLog(#"teamID: %#\n\n", team.teamID);
}
NSFetchRequest *fetchRequestBatting = [[NSFetchRequest alloc] init];
NSEntityDescription *entityBatting = [NSEntityDescription entityForName:#"Batting" inManagedObjectContext:self.managedObjectContext];
[fetchRequestBatting setEntity:entityBatting];
NSArray *fetchedObjectsBatting = [self.managedObjectContext executeFetchRequest:fetchRequestBatting error:&error];
NSLog(#"Number of records in battingFiles.json - %d", (int)[fetchedObjectsBatting count]);
for (id b in BATTING_UVWXYZ) {
Batting *batting = [NSEntityDescription insertNewObjectForEntityForName:#"Batting"
inManagedObjectContext:self.managedObjectContext];
batting.playerID = [b objectForKey:#"playerID"];
batting.h = [b objectForKey:#"h"];
batting.ab = [b objectForKey:#"ab"];
batting.hr = [b objectForKey:#"hr"];
batting.rbi = [b objectForKey:#"rbi"];
batting.sb = [b objectForKey:#"sb"];
batting.r = [b objectForKey:#"r"];
batting.bb = [b objectForKey:#"bb"];
batting.so = [b objectForKey:#"so"];
batting.yearID = [b objectForKey:#"yearID"];
batting.teamID = [b objectForKey:#"teamID"];
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
fetchedObjectsBatting = [self.managedObjectContext executeFetchRequest:fetchRequestBatting error:&error];
for (Batting *b in fetchedObjectsBatting) {
NSLog(#"playerID: %#", b.playerID);
NSLog(#"h: %#", b.h);
NSLog(#"ab: %#", b.ab);
NSLog(#"hr: %#", b.hr);
NSLog(#"rbi: %#", b.rbi);
NSLog(#"sb: %#", b.sb);
NSLog(#"r: %#", b.r);
NSLog(#"bb: %#", b.bb);
NSLog(#"so: %#", b.so);
NSLog(#"yearID: %#", b.yearID);
NSLog(#"teamID: %#\n\n", b.teamID);
}
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
#pragma mark - Core Data stack
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (NSURL *)applicationDocumentsDirectory {
// The directory the application uses to store the Core Data store file. This code uses a directory named "steindorf.Baseball_Stats" in the application's documents directory.
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Baseball_Stats" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Baseball_Stats.sqlite"];
NSLog(#"%#", storeURL);
NSError *error = nil;
NSString *failureReason = #"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = #"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:#"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this 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();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
#pragma mark - Core Data Saving support
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = 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();
}
}
}
#end
In the block below, you need to assign the team to batting.
batting.teams = {your_team_object}
Then you will be able to access the team information. You can create another fetch to Core Data using the teamID to retrieve the team object.
for (id b in BATTING_UVWXYZ) {
Batting *batting = [NSEntityDescription insertNewObjectForEntityForName:#"Batting"
inManagedObjectContext:self.managedObjectContext];
batting.playerID = [b objectForKey:#"playerID"];
batting.h = [b objectForKey:#"h"];
batting.ab = [b objectForKey:#"ab"];
batting.hr = [b objectForKey:#"hr"];
batting.rbi = [b objectForKey:#"rbi"];
batting.sb = [b objectForKey:#"sb"];
batting.r = [b objectForKey:#"r"];
batting.bb = [b objectForKey:#"bb"];
batting.so = [b objectForKey:#"so"];
batting.yearID = [b objectForKey:#"yearID"];
batting.teamID = [b objectForKey:#"teamID"];
NSPredicate *teamIDPredicate = [NSPredicate predicateWithFormat:#"teamID == %#", [b objectForKey:#"teamID"]];
[fetchRequestTeams setPredicate:predicate];
NSArray *fetchedSpecificTeam = [self.managedObjectContext executeFetchRequest:fetchRequestTeams error:&error];
batting.teams= [fetchedSpecificTeam objectAtIndex:0];
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}

Lightweight migration with iCloud

I have an app that can be run two ways: Using Local Storage or using iCloud. When I use local storage, my lightweight migration works fine, but when I choose iCloud, it causing all my data to be lost. Here is the code I use to initialize the persistent store coordinator:
NSMutableDictionary *options = [NSMutableDictionary dictionary];
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *ubContainer = [fm URLForUbiquityContainerIdentifier:nil];
NSURL *logsDir = [ubContainer URLByAppendingPathComponent:#"logsDir"];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
if ([[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsUseICloud]) {
// Construct the dictionary that tells Core Data where the transaction log should be stored
[options setObject:#"comcompanyappname" forKey:NSPersistentStoreUbiquitousContentNameKey];
[options setObject:logsDir forKey:NSPersistentStoreUbiquitousContentURLKey];
}
// Read in xcdatamodeld
model = [NSManagedObjectModel mergedModelFromBundles:nil];
psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSURL *nosyncDir = [ubContainer URLByAppendingPathComponent:#"appname.nosync"];
NSURL *storeURL;
if (ubContainer) {
[fm createDirectoryAtURL:nosyncDir withIntermediateDirectories:YES attributes:nil error:nil];
storeURL = [nosyncDir URLByAppendingPathComponent:#"store.data"];
}
else{
NSString *path = [self itemArchivePath];
storeURL = [NSURL fileURLWithPath:path];
}
NSError *error = nil;
[psc lock];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
[NSException raise:#"Open failed" format:#"Reason: %#", [error localizedDescription]];
}
[psc unlock];
// Create the managed object context
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:psc];
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
// The managed object context can manage undo, but we don't need it
[context setUndoManager:nil];

Strange Core Data Error During Migration

I'm absolutely pulling my hair out with Core Data after yet another bizarre error that I can't seem to solve.
This will be the fourth version of the Data model, the previous migrations have worked (albeit with some headaches).
All I'm trying to do is add a property of String type to an 'Engines' entity. I create a new version of the model (version 4) based on the current version (v3). I select the newly created version 4 as the 'Current model' and add the string property to the Engines entity. I then create a new mapping model, using v3 as the source and v4 as the target. I delete the previous Engines NSManagedObject subclass, and create a new one using the new, modified Engines entity, checking to make sure that the new String property is in the header file. I clean build the app and run it, and boom! I get this error, about 18 times:
{NSDetailedErrors=(
"Error Domain=NSCocoaErrorDomain Code=1570 \"The operation couldn\U2019t be completed. (Cocoa error 1570.)\" UserInfo=0x6015820 {NSValidationErrorObject= (entity: BodySet; id: 0x60ba670 ; data: ), NSValidationErrorKey=availableCar, NSLocalizedDescription=The operation couldn\U2019t be completed. (Cocoa error 1570.)}",
BodySet is another entity in the model, but I haven't touched it during this migration, so why is it causing all these errors?
I'm not sure if this is a help or not, but here's my Core Data code:
- (NSManagedObjectContext *) managedObjectContext {
if (managedObjectContext != nil) {
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
NSString *path = [[NSBundle mainBundle] pathForResource:#"CoreDataTest" ofType:#"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];
return managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
stringByAppendingPathComponent:#"<Project Name>.sqlite"]];
//get the DB from the Documents directory:
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: #"<Project Name>.sqlite"]];
NSLog(#"Loading DB at path: %#", [storeUrl path]);
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeUrl options:options error:&error]) {
/*Error for store creation should be handled in here*/
NSLog(#"Something went wrong....%#", [error description]);
}
return persistentStoreCoordinator;
}
Any help with this is very much appreciated.
i have fixed it ,maybe you can change "availableCar“ item to optional

Manual CoreData Migration with NSMigrationManager to append Data (preload)

I have a populated sqlite database in my app reousrce-folder. On startup I want to preload coredata-store with the data of this sqlite db. I use the NSMigrationManager in the persistantStoreCoordinator method. This works great at the first time and will append the data to the store. But it will append the data on each startup again, so the data will be duplicated, after the second startup. How can I solve this? In a database I would use primary keys, is there something similar in the data model? Or can I compare the entity-objects?
Thanks four your help, below the method I use:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:#"Raetselspass.sqlite"];
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"Raetselspass" ofType:#"sqlite"];
NSURL *defaultStoreUrl = [NSURL fileURLWithPath:defaultStorePath];
/*
Set up the store.
For the sake of illustration, provide a pre-populated default store.
*/
// CANNOT USE THIS BELOW: WILL WORK ONCE, BUT WHEN I WILL UPDATE THE APP WITH
// NEW DATA TO APPEND, THEN THIS WILL NOT WORK
// NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn’t exist, copy the default store.
// if (![fileManager fileExistsAtPath:storePath]) {
// if (defaultStorePath) {
// [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
// }
// }
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSError *error;
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
// Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort(); // Fail
}
//migration
rror:&error];
NSError *err = nil;
NSMigrationManager *migrator = [[NSMigrationManager alloc] initWithSourceModel:[self managedObjectModel] destinationModel:[self managedObjectModel]];
NSMappingModel *mappingModel = [NSMappingModel inferredMappingModelForSourceModel:[self managedObjectModel] destinationModel:[self managedObjectModel] error:&err];
NSError *err2;
if (![migrator migrateStoreFromURL:defaultStoreUrl
type:NSSQLiteStoreType
options:nil
withMappingModel:mappingModel
toDestinationURL:storeUrl
destinationType:NSSQLiteStoreType
destinationOptions:nil
error:&err2])
{
//handle the error
}
NSLog(#"import finished");
[migrator release];
return persistentStoreCoordinator_;
}
The code as provided will merge the default file if it is present in the documents folder. If you delete the file after you merge it, then it shouldn't load every time. You could set a user default flag to record if it had been previously merged.
A better solution would be to create a Core Data persistent store with the default data and include that in the app bundle. Upon first launch, copy that file to the documents folder and just assign it to the persistent store. That method would be faster and you wouldn't have to worry about the merge failing.

Resources