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
Related
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.
Sorry if the title is bad. What I'm trying to understand is: in the core data examples I have found online they explain how to use core data with nsfetchresultcontroller. But from what I understand nsfetchresultcontroller is made for table views. But I have only 2 regular view controllers.
It's really basic, I have 1 view controller for a create page to create a task, and another one which is the homepage with a label to show that single task that was created:
HomePageViewController.m:
#import "HomePageViewController.h"
#import "CreatTargetViewController.h"
#interface HomePageViewController ()
#property (weak, nonatomic) IBOutlet UILabel *currentTarget;
#end
#implementation HomePageViewController
- (IBAction)unwindToHomePage:(UIStoryboardSegue *)segue
{
CreatTargetViewController *source = (CreatTargetViewController *)[segue sourceViewController];
self.currentTarget.text = source.target.content;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
CreatTargetViewController.h:
#import <UIKit/UIKit.h>
#import "Targets.h"
#interface CreatTargetViewController : UIViewController
#property (nonatomic, strong) Targets *target;
#end
CreatTargetViewController.m:
#import "CreatTargetViewController.h"
#import "Targets.h"
#import "CoreDataStack.h"
#interface CreatTargetViewController ()
#property (weak, nonatomic) IBOutlet UIBarButtonItem *saveButton;
#property (weak, nonatomic) IBOutlet UITextView *myTextView;
#end
#implementation CreatTargetViewController
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.saveButton) return;
if (self.target != nil) {
self.myTextView.text = self.target.content;
}
}
- (void)insertNewTargetEntry
{
CoreDataStack *coreDataStack = [CoreDataStack defaultStack];
Targets *entry = [NSEntityDescription insertNewObjectForEntityForName:#"Targets" inManagedObjectContext:coreDataStack.managedObjectContext];
entry.content = self.myTextView.text;
[coreDataStack saveContext];
}
- (void)updateTargetEntry
{
self.target.content = self.myTextView.text;
CoreDataStack *stack = [CoreDataStack defaultStack];
[stack saveContext];
}
- (IBAction)saveWasPressed:(id)sender
{
if (self.target != nil) {
[self updateTargetEntry];
} else {
[self insertNewTargetEntry];
}
}
- (void)viewWillAppear:(BOOL)animated
{
[self.myTextView becomeFirstResponder];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
and another class for the core data stack:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface CoreDataStack : NSObject
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
+ (instancetype)defaultStack;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
CoreDataStack.m:
#import "CoreDataStack.h"
#implementation CoreDataStack
#pragma mark - Core Data stack
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
+ (instancetype)defaultStack
{
static CoreDataStack *defaultStack;
static dispatch_once_t onceToken;
dispatch_once (&onceToken, ^{
defaultStack = [[self alloc] init];
});
return defaultStack;
}
- (NSURL *)applicationDocumentsDirectory {
// The directory the application uses to store the Core Data store file. This code uses a directory named "digitalCrown.LaserApp" 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:#"LaserApp" 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:#"LaserApp.sqlite"];
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();
}
}
}
How do I communicate the data here?
I have created a Project in Xcode 5.1.1 without core data support.
Now i am trying to get the core data support.
Steps:
1) File -> New -> File -> Data Model -> Added.
It created : samplecd.xcdatamodeld
2) Added Entity:
myname type: String
3)
To do the changes in the AppDelegate.h and AppDelegate.m,
I have created one more project with 'core data' enabled, and copied
the below contents into the previous project.
AppDelegate.h
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
AppDelegate.m
- (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 - 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;
}
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"withcoredata" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"withcoredata.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];
}
ERROR:
I get the below compilation error:
"AppDelegate.m:122:35: Receiver 'NSManagedObjectContext' for class message is a forward declaration"
AppDelegate.m:122:34: Receiver type 'NSManagedObjectContext' for instance message is a forward declaration
How to solve this issue?
your core data model name is samplecd and your sqlite database name is withcoredata
both name should be similar for using core data in existing project.
Change the name and let me know if your problem is solved or not.
You need to import CoreData/CoreData.h in your AppDelegte.h file:
#import <CoreData/CoreData.h>
and in YourApp-Prefix.pch:
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#endif
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.
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.