Im adding to iCloud to an existing app. Syncing works fine however I need to exclude some entities, or come up with a work around as some of my core data is being duplicated.
eg:
CertificateColour is sent to a table view and each row is shown twice now.
CertificateType presents four options in a action sheet, now 8 rows are present, with each row having been duplicated once.
Im using https://github.com/mluisbrown/iCloudCoreDataStack for my core data sync.
I checked out Core data + iCloud: exclude certain attributes from sync? That suggested a couple things:
1. Creating a separate local and cloud store, sounds...promising but not sure how as this is my first attempt with iCloud and Core data.
2. The second suggestion was sync to an entity that includes a unique device identifier but this is deprecated and again unsure of the process with core data
AppDelegate.h
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#import "PersistentStack.h"
#interface ICAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UINavigationController *navigationController;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
Appdelegate.m
#interface ICAppDelegate () <DBSessionDelegate, DBNetworkRequestDelegate>
//iCloud
#property (nonatomic, strong) PersistentStack* persistentStack;
#property (nonatomic, strong) NSManagedObjectContext* managedObjectContext;
#end
#implementation ICAppDelegate
#synthesize window = _window;
#synthesize navigationController = _navigationController;
#synthesize managedObjectContext = __managedObjectContext;
#synthesize managedObjectModel = __managedObjectModel;
#synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//iCloud
self.persistentStack = [[PersistentStack alloc] initWithStoreURL:self.storeURL modelURL:self.modelURL];
self.managedObjectContext = self.persistentStack.managedObjectContext;
BOOL populateData = NO;
BOOL copyDb = YES;
// Copy DB to documents directory
if (copyDb == YES) {
NSString *srcPath = [[NSBundle mainBundle] pathForResource:#"myApp" ofType:#"sqlite"];
NSString *destPath = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:#"myApp.sqlite"];
if (![[NSFileManager defaultManager] fileExistsAtPath:srcPath]) {
DebugLog(#"Source file doesn't exist");
}
if (![[NSFileManager defaultManager] fileExistsAtPath:destPath]) {
DebugLog(#"Copying DB to documents directory");
NSError *error = nil;
[[NSFileManager defaultManager] copyItemAtPath:srcPath toPath:destPath error:&error];
if (error != nil) {
DebugLog(#"Copy failed %#", [error localizedDescription]);
}
}
}
/////*****ALL OF THIS IS DUPLICATED AND NEEDS EXCLUDING FROM ICLOUD BACK UP****////////////
if (populateData) {
DebugLog(#"Populating database");
NSManagedObjectContext *context = [self managedObjectContext];
Subscription *subscription = (Subscription *)[NSEntityDescription insertNewObjectForEntityForName:#"Subscription" inManagedObjectContext:context];
subscription.subscribed = #NO;
CertificateColour *red = (CertificateColour *)[NSEntityDescription insertNewObjectForEntityForName:#"CertificateColour" inManagedObjectContext:context];
red.name = #"Red";
red.redComponent = #1.0f;
red.greenComponent = #0.0f;
red.blueComponent = #0.0f;
CertificateColour *purple = (CertificateColour *)[NSEntityDescription insertNewObjectForEntityForName:#"CertificateColour" inManagedObjectContext:context];
purple.name = #"Purple";
purple.redComponent = #0.4f;
purple.greenComponent = #0.0f;
purple.blueComponent = #0.6f;
CertificateColour *green = (CertificateColour *)[NSEntityDescription insertNewObjectForEntityForName:#"CertificateColour" inManagedObjectContext:context];
green.name = #"Green";
green.redComponent = #0.0f;
green.greenComponent = #0.6f;
green.blueComponent = #0.2f;
CertificateColour *blue = (CertificateColour *)[NSEntityDescription insertNewObjectForEntityForName:#"CertificateColour" inManagedObjectContext:context];
blue.name = #"Blue";
blue.redComponent = #0.0f;
blue.greenComponent = #0.2f;
blue.blueComponent = #1.0f;
ICCertificateTypeManager *ctm = [ICCertificateTypeManager manager];
CertificateType *type = [ctm newCertificateType];
type.title = #"Works";
type.identifier = #(Works);
type = [ctm newCertificateType];
type.title = #"Type1";
type.identifier = #(Type1);
type = [ctm newCertificateType];
type.title = #"Type2";
type.identifier = #(Type2);
type = [ctm newCertificateType];
type.title = #"Type4";
type.identifier = #(Type3);
[self saveContext];
}
if ([[ICWebServiceClient sharedInstance] isLoggedIn])
{
DebugLog(#"User is logged in ");
}
////////////////////////////////////////////////////////////
return YES;
}
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
LogCmd();
if ([[DBSession sharedSession] handleOpenURL:url]) {
if ([[DBSession sharedSession] isLinked]) {
DebugLog(#"handling url");
}
return YES;
}
return NO;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.managedObjectContext save:NULL];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
[self saveContext];
}
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#pragma mark - DBSessionDelegate
- (void)sessionDidReceiveAuthorizationFailure:(DBSession*)session userId:(NSString *)userId
{
LogCmd();
}
#pragma mark - DBNetworkRequestDelegate
static int outstandingRequests;
- (void)networkRequestStarted {
outstandingRequests++;
if (outstandingRequests == 1) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
}
}
- (void)networkRequestStopped {
outstandingRequests--;
if (outstandingRequests == 0) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
}
#pragma mark - Core Data stack
// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil) {
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil) {
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"myApp" withExtension:#"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"myApp.sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#pragma mark - iCloud store
- (NSURL*)storeURL
{
NSURL* documentsDirectory = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
return [documentsDirectory URLByAppendingPathComponent:#"myApp.sqlite"];
}
- (NSURL*)modelURL
{
return [[NSBundle mainBundle] URLForResource:#"myApp" withExtension:#"momd"];
}
#end
Using multiple persistent stores is really the only option for excluding specific entity types from iCloud. You do that by calling addPersistentStoreWithType more than once on the same persistent store coordinator but with different persistent store files (it's called a coordinator because it can coordinate between multiple persistent stores). Use iCloud options for one of the stores but not for the other.
You can either use two separate managed object models with different entities, or you can use a single model with different configuration options. Either is effective.
The problem you'll probably have with this is that you can't create relationships between instances in different persistent store files. (Technically you can create them, you just can't save them, which in most cases makes them useless). Your CertificateType entity sounds like it would have relationships to other instances, but that's not going to work with multiple stores.
What you can do instead is sync every object but add code to detect the duplicates and deal with them. There was a good example of this in Apple's "SharedCoreData" sample app from the "Using iCloud with Core Data" session at WWDC 2012, but I can't find a copy of that online right now. You'd do something like
Wait on NSPersistentStoreDidImportUbiquitousContentChangesNotification
When it arrives, look at the notification's userInfo to see if any of your CertificateType objects are included.
If so, do a fetch for that entity to find and match up duplicates
Clean up those duplicates in whatever way makes sense for your app.
Update: I forgot that I had done a blog post which covers this in more detail. I also found a link to the WWDC 2012 sample code bundle (link requires current developer account) which includes SharedCoreData. A lot of what's in that demo is obsolete, but the duplicate removal code is as valid as ever.
Related
The persistant container goes nil. When I run program I get this error : Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'AppData'
I have found similar questions on stackoverflow but haven't got any problem solving answer that is why I'm posting this question again.
Here is my code :
-(void)saveData
{
NSManagedObjectContext *localContext=((AppDelegate*)[[UIApplication sharedApplication] delegate]).persistentContainer.viewContext;
// [self initPer];
// UIApplication *app = [UIApplication sharedApplication];
// AppDelegate *delg = (AppDelegate *)app.delegate;
// NSManagedObjectContext *localContext = delg.getManagedObj;
// AppData *appData1= [NSEntityDescription insertNewObjectForEntityForName:#"AppData" inManagedObjectContext:localContext];
// NSManagedObjectContext *localContext = _del.persistentContainer.viewContext;
AppData *appDta = [NSEntityDescription insertNewObjectForEntityForName:#"AppData" inManagedObjectContext:localContext];
NSString *value = [valueArray1 componentsJoinedByString:#" "];
NSString *commandKey = [keyArray1 componentsJoinedByString:#" "];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
[dictionary setObject:value forKey: nsDate];
NSLog(#"%#", dictionary);
appDta.key = commandKey;
appDta.details = dictionary;
}
AppDelegate.h :
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (readonly, strong) NSPersistentContainer *persistentContainer;
- (void)saveContext;
-(NSManagedObjectContext*)getManagedObj;
#end
AppDelegate.m :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
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 invalidate graphics rendering callbacks. 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 active 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];
}
-(NSManagedObjectContext*)getManagedObj{
return self.persistentContainer.viewContext;
}
#pragma mark - Core Data stack
#synthesize persistentContainer = _persistentContainer;
- (NSPersistentContainer *)persistentContainer {
// The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
#synchronized (self) {
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:#"Model"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
// 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.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
NSLog(#"Unresolved error %#, %#", error, error.userInfo);
abort();
}
}];
}
}
return _persistentContainer;
}
#pragma mark - Core Data Saving support
- (void)saveContext {
NSManagedObjectContext *context = self.persistentContainer.viewContext;
NSError *error = nil;
if ([context hasChanges] && ![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.
NSLog(#"Unresolved error %#, %#", error, error.userInfo);
abort();
}
}
You can see that some lines are commented, I kept it to show that I've also tried it but haven't got any result.
As mentioned HERE
Set
AppDelegate.h :
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (readonly, strong) NSPersistentContainer *persistentContainer;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSManagedObjectContext *)getManagedObj;
AppDelegate.m :
#pragma mark - Core Data stack
#synthesize persistentContainer = _persistentContainer;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
#synthesize managedObjectModel = _managedObjectModel;
- (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 (_managedObjectContext != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Model" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Model.sqlite"];
NSLog(#"DB Path==> %#",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 *)getManagedObj {
// 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] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
Then try with your commented code like as under :
AppDelegate *objAppDel = (AppDelegate *)[[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [objAppDel managedObjectContext];
AppData *objAppData = [NSEntityDescription insertNewObjectForEntityForName:#"AppData" inManagedObjectContext:context];
I am working on Objective-C with CoreData, i am getting below error...
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An NSManagedObject of class
'NSManagedObject' must have a valid NSEntityDescription.'
I added CoreData to my project. I created saveData method in viewControllerA and i called it in viewControllerB.
In this scenario I am getting error, if I call saveData method in viewDidLoad of viewControllerA it's working properly.
In AppDelegate.h
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
In AppDelegate.m
#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 "com.brninfotech._607_introToCoreDataFinal" 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:#"VehicleNumberDataBase" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and returns 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:#"VehicleNumberDataBase.sqlite"];
// NSLog(#"StoreURL is %#",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] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_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();
}
}
}
in viewControllerA viewDidLoad
self.ad = (AppDelegate *)[[UIApplication sharedApplication]delegate];
self.VehicleNumberED = [NSEntityDescription entityForName:#"VehicleNumberEntity" inManagedObjectContext:self.ad.managedObjectContext];
- (void)saveData {
NSManagedObject * managedObj = [[NSManagedObject alloc]initWithEntity:self.VehicleNumberED insertIntoManagedObjectContext:self.ad.managedObjectContext];
[managedObj setValue:self.textFieldString forKey:#"vehicleNumberAtt"];
NSError * errorObj;
[self.ad.managedObjectContext save:&errorObj];
if (errorObj) {
NSLog(#"Something goes wrong");
}else {
NSLog(#"Saved Successfully");
}
NSFetchRequest * fetReq = [NSFetchRequest fetchRequestWithEntityName:#"VehicleNumberEntity"];
NSError * fetchErrorObj;
self.storedDataArray = [self.ad.managedObjectContext executeFetchRequest:fetReq error:&fetchErrorObj];
NSLog(#"array count is %lu", self.storedDataArray.count);
for (int i=0; i<self.storedDataArray.count; i++) {
self.storedManagedObj = [self.storedDataArray objectAtIndex:i];
self.vehicleNumberArray = [self.storedManagedObj valueForKey:#"vehicleNumberAtt"];
}
NSLog(#"Vehicle number is : %#", [self.storedManagedObj valueForKey:#"vehicleNumberAtt"]);
}
in ViewVontrollerB
- (IBAction)saveVehicleNumberButton:(UIButton *)sender {
VehicleDetailsViewController *vedvc = [[VehicleDetailsViewController alloc]init];
vedvc = [self.storyboard instantiateViewControllerWithIdentifier:#"VeDVC"];
vedvc.textFieldString = self.vehicleNumberTextField.text;
[vedvc saveData];
[self.navigationController pushViewController:vedvc animated:YES];
}
The issue here is that you are executing [vedvc saveData] before displaying the vedvc view controller. At this point, vedvc has not been displayed, so its viewDidLoad has not yet been executed. Consequently self.ad and self.VehicleNumberED are both nil. Hence the error: the entity description is nil.
The simplest fix would be to move the initialisation of those two variables (ad and VehicleNumberED) to the saveData method. But you might do better to rethink your code structure.
I'm quite new to Objective-C and I'm trying to mess around with Core Data. I have the following App Delegate interface and implementation:
#import <UIKit/UIKit.h>
#interface SDTAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveManagedObjectContext;
- (NSManagedObjectContext *)setupManagedObjectContext;
- (NSManagedObjectModel *)setupManagedObjectModel;
- (NSPersistentStoreCoordinator *)setupPersistentStoreCoordinator;
- (NSURL *)applicationDocumentsDirectory;
#end
Implementation
#import "SDTAppDelegate.h"
#import "ToDoItem.h"
#implementation SDTAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Get the managed object context and associate it to the app delegate
self.managedObjectContext = [self setupManagedObjectContext];
return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application
{
[self saveManagedObjectContext];
}
/**
* Save the MOC!
*/
- (void)saveManagedObjectContext
{
NSError *error = nil;
if (self.managedObjectContext != nil)
{
if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error])
{
/*
THIS NEEDS TO BE REPLACED
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#pragma mark - Core Data stack
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)setupManagedObjectContext
{
if (self.managedObjectContext != nil)
{
return self.managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self setupPersistentStoreCoordinator];
if (coordinator != nil)
{
self.managedObjectContext = [[NSManagedObjectContext alloc] init];
[self.managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return self.managedObjectContext;
}
/**
* Return the managed object model. If it doesn't exist, create it.
*/
- (NSManagedObjectModel *)setupManagedObjectModel
{
if (self.managedObjectModel != nil)
{
return self.managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Model" withExtension:#"momd"];
self.managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return self.managedObjectModel;
}
/**
* Return the persistent store coordinator. If it doesn't exist, create it.
*/
- (NSPersistentStoreCoordinator *)setupPersistentStoreCoordinator
{
if (self.persistentStoreCoordinator != nil)
{
return self.persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Model.sqlite"];
NSError *error = nil;
self.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self setupManagedObjectModel]];
if (![self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:nil
error:&error])
{
/*
THIS NEEDS TO BE REPLACED
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return self.persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
/**
* Return the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#end
And then in my controller I have the following to save a new model:
// Take the managed object context from the app delegate
SDTAppDelegate *appDelegate = (SDTAppDelegate *)[UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = appDelegate.managedObjectContext;
// Add the new item
ToDoItem *newItem = [NSEntityDescription insertNewObjectForEntityForName:#"ToDoItem" inManagedObjectContext:context];
newItem.item = self.textField.text;
newItem.completed = 0;
No matter what happens I can't get the application to save. It shows up fine in the interface, but when I quit and restart the data is no longer there. I'm guessing this is something wrong with my persistent storage?
You should save the context in order to save in the persistent store.
NSError *error;
[context save:&error];
Hope it helps. Cheers
This code is supposed to save my data to core data in TestViewController.m file:
//Property
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
//Methods
- (void)saveUser:(NSString *) username withEmail:(NSString *) email withName:(NSString *) name
{
//1
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
//2
self.managedObjectContext = appDelegate.managedObjectContext;
User *coreDataUser = [NSEntityDescription insertNewObjectForEntityForName:#"User" inManagedObjectContext:self.managedObjectContext];
coreDataUser.username = username;
coreDataUser.email = email;
coreDataUser.name = name;
NSError *error;
if (![self.managedObjectContext save:&error])
{
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
//In my save user method I have stuff that is done in another thread but then this is called:
// Add in any UIKit code here on main queue
dispatch_async(dispatch_get_main_queue(), ^{
if (isUnique == YES)
{
[self saveUser:[emailStr lowercaseString] withEmail:emailStr withName:nameStr];
My code always crashes on:
ser *coreDataUser = [NSEntityDescription insertNewObjectForEntityForName:#"User" inManagedObjectContext:self.managedObjectContext];
It says signal SIGABRT in main.
I am following this tutorial: http://www.codigator.com/tutorials/ios-core-data-tutorial-with-example/
And running in ios 7.
What am I missing?
I'm tracing the appDelegate.m code now but it looks like this:
// 1
- (NSManagedObjectContext *) managedObjectContext {
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_ managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return _managedObjectContext;
}
//2
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return _managedObjectModel;
}
//3
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil)
{
return _persistentStoreCoordinator;
}
NSString *test = [self applicationDocumentsDirectory];
NSString *test2 = test;
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"HappyPeople.sqlite"]];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
i f (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error])
{
/*Error for store creation should be handled in here*/
}
return _persistentStoreCoordinator;
}
- (NSString *)applicationDocumentsDirectory
{
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
Seems like the sqllite db file gets created.
The exception I am getting is this:
NSException * name:#"NSInternalInconsistencyException" reason:#"+entityForName: could not locate an entity named 'Users' in this model." 0x0895ee20
I know this question is a little old...
This is the exception I get when I change the schema of the object model and try to use a file with the old schema. The sqllite db on disk may not match your apps schema.
I have been using CoreData with a UIManagedDocument so it is a little different. There you have options to automatically migrate on the open.
Also, early on in the comments it was asked whether the ManagedObjectContext was nil. I believe that this should be checked before you call the insert. Are we sure all of the core data setup is on the main queue? It can take a little time to open. (Again with UIManagedDocument is explicitly on another thread.)
This is my CoreDataManagerClass.
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface RTC_CoreDataManager : NSObject
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
-(void)insertEntity:(NSString *)entityName arrayOfManagedObject:(NSMutableArray *)array;
+(RTC_CoreDataManager *)shredInstance;
#end
#import "RTC_CoreDataManager.h"
RTC_CoreDataManager *obj_RTC;
#implementation RTC_CoreDataManager
#synthesize managedObjectContext = __managedObjectContext;
#synthesize managedObjectModel = __managedObjectModel;
#synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
+(RTC_CoreDataManager *)shredInstance{
if (obj_RTC == nil) {
obj_RTC = [[RTC_CoreDataManager alloc]init];
}
return obj_RTC;
}
#pragma mark - Core Data stack
- (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;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"RTC" withExtension:#"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"RTC.sqlite"];
NSError *error = nil;
if (![[NSFileManager defaultManager] copyItemAtURL:storeURL toURL:[NSURL alloc] error:&error]) {
NSLog(#"Oops, could copy preloaded data");
}
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
-(void)insertEntity:(NSString *)entityName arrayOfManagedObject:(NSMutableArray *)array
{
NSManagedObjectContext *backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
for (id object in array)
{
[backgroundMOC performBlockAndWait:^
{
NSError *error;
if (![__managedObjectContext save:&error])
{
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}];
}
}
#end
And this is my code in another controller.
-(void)viewDidLoad
{
[super viewDidLoad];
appDele_Obj = (RTC_AppDelegate *)[[UIApplication sharedApplication] delegate];
appDele_Obj.entityArray=[[NSMutableArray alloc]init];
for (int i=0; i<10; i++)
{
Survey *objSurvey = [NSEntityDescription
insertNewObjectForEntityForName:#"Survey"
inManagedObjectContext:[RTC_CoreDataManager shredInstance].managedObjectContext]; [objSurvey setFirstName:#"1"];
[objSurvey setLastName:#"2"];
[objSurvey setEmpId:#"3"];
[objSurvey setLanguage:#"Hindi"];
[objSurvey setCountry:#"India"];
[objSurvey setSurveyNo:[NSNumber numberWithInt:2]];
[[appDele_Obj entityArray] addObject:objSurvey];
[objSurvey release];
}
//[objSurvey release];
[[RTC_CoreDataManager shredInstance] insertEntity:#"Survey" arrayOfManagedObject:[appDele_Obj entityArray]];
if ([[appDele_Obj entityArray]count] >0) {
[[appDele_Obj entityArray] removeAllObjects];
}
}
So My question is,
If I call method removeAllObjects on [appDele_Obj entityArray] crashing the application. Why I can not call [[appDele_Obj entityArray] removeAllObjects];
in above approach. Any one can help me to solve this crash.
Thanks.
It's a simple case of memory mis-management. This creates an autoreleased object:
Survey *objSurvey = [NSEntityDescription
insertNewObjectForEntityForName:#"Survey"
inManagedObjectContext:[RTC_CoreDataManager shredInstance].managedObjectContext];
Then you do this:
[[appDele_Obj entityArray] addObject:objSurvey];
[objSurvey release];
You should not be calling release here. The object is autoreleased-- calling release is not only unnecessary, it's dangerous. Later on when you remove the objects from the array, you end up over-releasing every object in it. That causes the crash.
A few other things from the code:
Calling save: on a managed object context in a loop is unnecessary unless you're making new changes on each pass through the loop. Your insertEntity:arrayOfManagedObject: method is doing a lot of unnecessary work.
The array in viewDidLoad is not necessary or useful for what you're doing. You've created the objects, and they're in the managed object context. Once you finish setting the attributes of those objects, you don't need to keep references. Keep adding objects until you're done, then tell the managed object context to save.
It's a minor detail, but you named a method that creates a singleton shredInstance. "Shred" is almost exactly the opposite of what you're doing in that method. You probably meant sharedInstance.