Core Data is empty after app restart - ios

When I start app and enter some data to Core Data via UITextField, they are displayed correctly in UITableView. Problem is when I restart the app, all data from Core Data is lost... Here is my code.
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
_managedObjectContext = [appDelegate managedObjectContext];
_managedObjectModel = [appDelegate managedObjectModel];
_persistentStoreCoordinator = [appDelegate persistentStoreCoordinator];
}
- (IBAction)saveButtonPressed:(id)sender {
Truck *truck = [NSEntityDescription insertNewObjectForEntityForName:#"Truck" inManagedObjectContext:_managedObjectContext];
[truck setModel:self.tField.text];
}

Once you create your truck object, you must save the context so that it gets written to the database.
- (IBAction)saveButtonPressed:(id)sender {
Truck *truck = [NSEntityDescription insertNewObjectForEntityForName:#"Truck" inManagedObjectContext:_managedObjectContext];
[truck setModel:self.tField.text];
[_managedObjectContext save:nil]; // you should provide an NSError object
}

Related

Coredata Fetched Results Controller save with child NSPrivateQueueConcurrencyType context

I have UICollectionViewController with <NSFetchedResultsControllerDelegate> and CoreData Singleton manager. So when I trying to update some Title of my object I see error.
CollectionViewController.m
#interface CollectionViewController ()<NSFetchedResultsControllerDelegate>
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#property (strong, nonatomic) NSManagedObjectContext* managedObjectContext;
#implementation CollectionViewController
- (NSManagedObjectContext*) managedObjectContext {
if (!_managedObjectContext) {
_managedObjectContext = [[CoreDataManager sharedManager] managedObjectContext];
}
return _managedObjectContext;
}
-(void)pushTheButton: (UIButton*) sender{
NSIndexPath *indexPath = [self.collectionView indexPathForCell:(PKMapObjectCVCell *)sender.superview.superview];
SomeObjectClass* object = [self.fetchedResultsController objectAtIndexPath:indexPath];
[[CoreDataManager sharedManager] changeValueForObject: object.objectID];
}
CoreDataManager.m
#implementation CoreDataManager
#synthesize mainPrivateManagedObjectContext = _mainPrivateManagedObjectContext;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
+(CoreDataManager*) sharedManager{
static CoreDataManager* manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[CoreDataManager alloc] init];
});
return manager;
}
- (void) changeValueForObject:(NSManagedObjectID*) myobjectID{
NSManagedObjectContext * bgcontext = [self getContextForBGTask];
SomeObjectClass * editableObject = [bgcontext objectWithID:myObjectID];
editableObject.title = #"New Title";
// [bgcontext updatedObjects];
[self saveContextForBGTask:bgcontext];
}
- (void)saveContextForBGTask:(NSManagedObjectContext *)bgTaskContext {
if (bgTaskContext.hasChanges) {
[bgTaskContext performBlockAndWait:^{ //error on this line:
[error] error: Serious application error. Exception was caught during
Core Data change processing. This is usually a bug within an observer
of NSManagedObjectContextObjectsDidChangeNotification. The left hand
side for an ALL or ANY operator must be either an NSArray or an NSSet.
with userInfo (null) CoreData: error: Serious application error.
Exception was caught during Core Data change processing. This is
usually a bug within an observer of
NSManagedObjectContextObjectsDidChangeNotification. The left hand
side for an ALL or ANY operator must be either an NSArray or an NSSet.
with userInfo (null) 2018-03-21 17:07:42.644646+0400
AppName[17860:3506816] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: 'The left hand side
for an ALL or ANY operator must be either an NSArray or an NSSet.
NSError *error = nil;
[bgTaskContext save:&error];
}];
[self saveDefaultContext:YES]; // Save default context
}
}
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
_mainPrivateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_mainPrivateManagedObjectContext setPersistentStoreCoordinator:coordinator];
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setParentContext:_mainPrivateManagedObjectContext];
return _managedObjectContext;
}
- (NSManagedObjectContext *)getContextForBGTask {
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:_managedObjectContext];
return context;
}
So, what I am doing wrong?
code delete object, is working fine:
- (void) switchObjectLike:(NSManagedObjectID*) mapObjectID{
NSManagedObjectContext * bgcontext = [self getContextForBGTask];
PKMapObj * mapObject = [bgcontext objectWithID:mapObjectID];
[bgcontext deleteObject:mapObject];
[self saveContextForBGTask:bgcontext];
}
So, problem was with predicate in NSFetchedResultsController. When some content was updated, NSFetchedResultsController preparing to reload collection view, and before call this method:
-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
it was crashed, but never shown error with it. Thanks everybody!

iOS - update multiple CoreData entities & contexts

I am using CoreData in my app and I have two main entities, let's say Cats and Dogs.
I have this method that I use to initialise my context:
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
It refers to this method in my App Delegate:
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
Now, at some point, I have to update some data in my Cats entity.
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Cats"];
NSMutableArray *catsArrayData = [[context executeFetchRequest:fetchRequest error:nil] mutableCopy];
NSManagedObject *aCat = [catsArrayData objectAtIndex:i];
NSMutableArray *catsArray = [aCat valueForKey:#"cat"];
[catsArray addObject:responseData];
[aCat setValue:catsArray forKey:#"cat"];
NSError *error = nil;
[context save:&error];
Then, I want to do the same for my Dogs entity. So I use the same code, but for the dogs entity. It's in another part of my code, so I have to redefine:
NSManagedObjectContext *context = [self managedObjectContext];
But the problem is that even though I save this second context, it is actually not saved. The data isn't there. How can I resolve this issue?
You need implement your own change notification mechanism, This is good source to learn it. Multi-Context CoreData.

managedObjectContext not being called on launch

I am modifying an existing Core Data app to iCloud. My problem is that when I try to load seed data after detecting an initial app launch in the appDelegate, my first [NSEntityDescription insertNewObjectForEntityForName: inManagedObjectContext:] statement throws the error "'NSInvalidArgumentException', reason: '+entityForName:XXX nil is not a legal NSManagedObjectContext parameter searching for entity name 'XXX''" I'm sure the inManagedObjectContext parameter I'm passing is the correct one, but sure enough, it's nil in debugger.
Part of my trouble is that I don't understand what cues the app to call the boilerplate core data -managedObjectContext, -managedObjectModel, and -persistentStoreCoordinators methods. The app always seemed to call the methods and instantiate these objects automatically whenever they were required.
The core data stack is basically the standard stuff from a core data app template, with the iCloud option added to persistentStoreCoordinator, and a branch for migrating existing data. Here's the code; trying to limit it to essential elements:
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Notification registrations
[self register_iCloudNotifications];
// Data from defaults
BOOL _firstLocalLaunch = ...
BOOL _update =
BOOL _iCLoudDataSeeded = ...
// FIRST APP LAUNCH LOCALLY; FIRST iCLOUD LAUNCH ANYWHERE
// This is the code that's calling initializeSeedData and getting the error
if (_firstLocalLaunch && !_iCloudDataSeeded) {
[self initializeSeedData];
... update defaults
} else if {
... code for update launch and normal launch
// Safety check for seed data in persistent store; if none, initialize.
NSFetchRequest *modelFetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *modelEntity = [NSEntityDescription entityForName:#"entity" inManagedObjectContext:self.managedObjectContext];
[modelFetchRequest setEntity:modelEntity];
NSArray *fetchResults = [_managedObjectContext executeFetchRequest:modelFetchRequest error:nil];
if (!fetchResults.count) {
NSLog(#"Safety catch: seed data missing");
[self initializeSeedData];
}
return YES;
}
- (void)initializeSeedData
{
SWSEntity *entity1 = [NSEntityDescription insertNewObjectForEntityForName:#"Entity" inManagedObjectContext:_managedObjectContext]; // THIS IS WHATS THROWING THE ERROR
entity.name = #"First seed data item";
[_managedObjectContext save:nil];
}
- (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:#"model" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
NSLog(#"exists; returning");
return _persistentStoreCoordinator;
}
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// NO UPDATE FROM PREVIOUS
if (!_update) {
NSLog(#"Persistent store: adding");
[self add_iCloudPersistentStore];
// UPDATE FROM PREVIOUS VERSION
} else {
NSLog(#"Persistent store: migrating");
...code for migrating existing store to iCloud; not called with this issue
}
return _persistentStoreCoordinator;
}
- (void)add_iCloudPersistentStore
{
NSError *error = nil;
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:[self get_iCloudStoreURL]
options:[self iCloudPersistentStoreOptions]
error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}
- (NSDictionary *)iCloudPersistentStoreOptions
{
return #{NSPersistentStoreUbiquitousContentNameKey: #"myAppStore",
NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES};
}
Interesting thing: If I comment out the [self initializeSeedData] after detecting a first launch, the "safety catch" for adding the data executes, and creates the seed data just fine! The only thing I can figure that's different is that I'm executing a fetchRequest on the managed object context first... somehow the _managedObjectContext is instantiated when the fetch is executed, and still around for [self initializeSedData]. Why would that happen?

SIGABRT when saving to managed object context in core data

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.)

Core Data Detail View with relationship

I have set up a 1 to many relationship on my core data entities. I am trying to show the detailview copy of the associated data. Currently I have the prepareforseague: method working with the original entity(Routines), however I am at a lose as to how to show the linked entity (RoutinesDetails).
FBCDRoutineViewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Routines"];
self.routines = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"UpdateDevice"]) {
NSManagedObject *selectedDevice = [self.routines objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
FBCDRoutineViewController *destViewController = segue.destinationViewController;
destViewController.routines = selectedDevice;
}
FBCDRoutineDetailViewController
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"RoutinesDetails"];
self.routines = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
}
- (void)viewDidLoad
{
[[self navigationController] setNavigationBarHidden:NO animated:YES];
[super viewDidLoad];
// Do any additional setup after loading the view.
if (self.routines) {
[self.testLabel setText:[self.routines valueForKey:#"routinename"]];
}
}
FBCDRoutineDetailViewController
#property (strong) NSManagedObject *routines;
This is my first time with core data and I am looking at how to show the Details entity. Am I Close to getting it working? If not can I get directed at to what I should be looking at.
Any suggestions?
If I understand your problem correctly, you want to display all RoutinesDetails objects
that are related to the Routines object passed in prepareForSegue.
Then you would declare two properties in the FBCDRoutineDetailViewController:
#property (strong) NSManagedObject *routines; // the passed object
#property (strong) NSManagedObject *routineDetails; // the displayed details objects
and fetch them like this:
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"RoutinesDetails"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"routineinfo == %#", self.routines];
[fetchRequest setPredicate:predicate];
NSError *error;
self.routineDetails = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
self.routineDetails is now the data source array for the details view.
(Remark: For displaying the result set of a Core Data request in a table view,
you might also consider to use a NSFetchedResultsController.)
I think I see several problems--mostly related to the timing of these various calls.
I believe viewDidLoad is called on your detail view before the prepareForSegue is called. So your code in viewDidLoad is trying to display data about your detail item before it has been set.
Then the code in viewDidAppear looks to be overwriting the value you set in prepareForSegue, which doesn't make sense to me (although by this time the view is already displayed and it's not going to affect the label you tried to set in viewDidLoad).
Also, executeFetchRequest: returns an NSArray, not an NSManagedObject, so assigning the result of your fetch to your NSArray property is a BAD idea.

Resources