managedObjectContext question - iphone

I have an app which is a UITabBarController, I have defined two subviews
Both tabs have their Class attribute in the Identity Inspector set to UINavigationController.
Now i have managed to get this far with my coding after VERY LONG trials.
- (void)viewDidLoad {
[super viewDidLoad];
myAppDelegate *appDelegate = (myAppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = appDelegate.managedObjectContext;
{
NSError *error = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"User" inManagedObjectContext:self.managedObjectContext]];
NSArray *fetchedItems = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSEntityDescription *entityDesc =
[NSEntityDescription entityForName:#"User" inManagedObjectContext:self.managedObjectContext];
// replace the old data with new. this DOESNT WORK
if (fetchedItems.count > 0)
{
Usr *newUsr;
for (newUsr in fetchedItems)
{
if ([newUsr.name isEqualToString:#"Line One"])
{
newUsr.uName = #"Line One (new)";
}
}
}
//add a new default data. THIS ADDS DATA TO MY TABLEVIEW BUT IT DOESNT SAVE THEM TO THE SQLITE
User *addedDefaultdata = nil;
addedDefaultdata = [[User alloc] initWithEntity:entityDesc insertIntoManagedObjectContext:self.managedObjectContext];
addedDefaultdata.name = #"Added new 1";
[addedDefaultdata release];
}
NSError *error = nil;
if (![User.managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
and my appdelegate looks like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[application setStatusBarStyle:UIStatusBarStyleBlackOpaque];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
}
now I cannot quire the "User" at all! although i get no errors or warnings!
Any suggestions would be much appreciated!
Thanks

It seems that you may be asking how to update to CoreData?
If so, you need to use the save: method on NSManagedObjectContext, like this:
NSError *error;
[managedObjectContent save:&error];
if (error) {
...
}

Related

Core Data Crash during Save without error. Only one Context and only main thread

I'm simply trying to delete three nsmanagedobject from an entity, as i already do in other application,where all went ok. This time core data seems to crash during save, there's no error, i'm using the app delegate context in all the app, so i think that isn't a multiple context problem... I have tried a check with [NSThread isMainThread] , during the save i'm in the main thread, so isn't a threading problem... What's wrong in my code?
-(void)EraseStore{
if (contesto == nil) {
contesto = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
NSError *error=nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Store" inManagedObjectContext:contesto];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [contesto executeFetchRequest:fetchRequest error:&error];
NSString *Store1=[NSString stringWithFormat:#"%#",#"55"];
NSString *Store2=[NSString stringWithFormat:#"%#",#"63"];
NSString *Store3=[NSString stringWithFormat:#"%#",#"11"];
for (int i=0; i<[fetchedObjects count]; i++) {
NSString *StoreId=[NSString stringWithFormat:#"%#",[[fetchedObjects objectAtIndex:i]valueForKey:#"id"]];
if ([StoreId isEqualToString:Store1] || [StoreId isEqualToString:Store2]|| [StoreId isEqualToString:Store3]) {
[contesto deleteObject:[fetchedObjects objectAtIndex:i]];
}
}
NSError *error1 = nil;
BOOL success = [contesto save:&error1];
if (!success) {
NSLog(#"Unresolved error2 %#, %#", error1, [error1 userInfo]);
}
else{
NSLog(#"saved");
}
}
How I create my context:
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
The error message I am getting:
Unresolved error2 Error Domain=NSCocoaErrorDomain Code=133020 "The operation couldn’t be completed. (Cocoa error 133020.)" UserInfo=0x23cf00 {conflictList=( "NSMergeConflict (0x23cdc0) for NSManagedObject (0x234960) with objectID '0x2da8b0 ' with oldVersion = 1 and newVersion = 2 and old object snapshot =....
EDIT
In database structure i haven't set any relationship between tables.

Delete object in Core Data

How I can delete an object which I had added before with this code. Its a favorites section, in the begin, I add a gray star which adds an object coming from a fetch. Then It turns yellow and the backwards method should be star yellow = deletes.
But I have no idea how to do this.
-(IBAction)inFavoris:(id)sender {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *favorisObj = [NSEntityDescription
insertNewObjectForEntityForName:#"Favoris"
inManagedObjectContext:context];
[favorisObj setValue:idTaxi forKey:#"idTaxi"];
[favorisObj setValue:nomTaxi forKey:#"nomTaxi"];
[favorisObj setValue:taxiCB forKey:#"cb"];
[favorisObj setValue:taxiAvion forKey:#"avion"];
[favorisObj setValue:taxiColis forKey:#"colis"];
[favorisObj setValue:taxiHandicape forKey:#"handicape"];
[favorisObj setValue:taxiHoraires forKey:#"horaire"];
[favorisObj setValue:lugagge forKey:#"lugagge"];
[favorisObj setValue:luxury forKey:#"luxury"];
[favorisObj setValue:languesParlees forKey:#"langues"];
[favorisObj setValue:taxiNote forKey:#"note"];
[favorisObj setValue:taxiPassengers forKey:#"passenger"];
[favorisObj setValue:taxiVote forKey:#"etoiles"];
[favorisObj setValue:taxiTel forKey:#"tel"];
[self.view addSubview:favorisB];
}
UPDATE
I made this method.. It gets the job done :)
-(IBAction)outFavoris:(id)sender {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSString *testEntityId = idTaxi;
NSManagedObjectContext *moc2 = [appDelegate managedObjectContext];
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
fetch.entity = [NSEntityDescription entityForName:#"Favoris" inManagedObjectContext:moc2];
fetch.predicate = [NSPredicate predicateWithFormat:#"idTaxi == %#", testEntityId];
NSArray *array = [moc2 executeFetchRequest:fetch error:nil];
for (NSManagedObject *managedObject in array) {
[moc2 deleteObject:managedObject];
}
[self.view addSubview:favorisO];
}
Its quite simple :)
[context deleteObject:favorisObj];
And the bad object is all gone.
Update
You'd just reverse it with something like this if you need a button to delete the object.
-(IBAction)removeFavoris:(id)sender {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
[context deleteObject:favorisObj];
}
Don't forget to save the Context after you have deleted a NSManagedObject. So here is the general code;
NSManagedObjectContext * context = [self managedObjectContext];
[context deleteObject:objectToDelete];
NSError * error = nil;
if (![context save:&error])
{
NSLog(#"Error ! %#", error);
}
In your case it should have the snippet after the for loop.
for (NSManagedObject *managedObject in array) {
[moc2 deleteObject:managedObject];
}
NSError * error = nil;
if (![context save:&error])
{
NSLog(#"Error ! %#", error);
}

Why doesn't my program enter the viewDidLoad method?

I am trying to test this program on use of Core data. Once again, this is an example from the Dave Marks book. It has four text fields on a view and it loads it by using core data to connect to the database.
The app was created as a window based application and then I added a viewController to it. The file's owner is a sub class of the custom viewController class that I have created.
When I execute it, the UIView comes up with a blank view with no text boxes or labels that I had created in the view.
I put a break point in the main method, it does not even go anywhere from there when I click on step into method button. When I place a break point on the viewDidLoad method, it does not even get to it.
Lastly I do not get any errors on the console. What is going on?
Here is the viewController class:
#import "PersistenceViewController.h"
#import "CoreDataPersistenceAppDelegate.h"
#implementation PersistenceViewController
#synthesize line1;
#synthesize line2;
#synthesize line3;
#synthesize line4;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
CoreDataPersistenceAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Line" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
if (objects == nil) {
NSLog(#"There was an error");
}
for (NSManagedObject *oneObject in objects) {
NSNumber *lineNum = [oneObject valueForKey:#"lineNum"];
NSString *lineText = [oneObject valueForKey:#"lineText"];
NSString *fieldName = [NSString stringWithFormat:#"line%d", [lineNum integerValue]];
UITextField *theField = [self valueForKey:fieldName];
theField.text = lineText;
}
[request release];
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:app];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
-(void) applicationWillResignActive:(NSNotification *)notification {
CoreDataPersistenceAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSError *error;
for (int i=1; i<=4; i++) {
NSString *fieldName = [NSString stringWithFormat:#"line%d",i];
UITextField *theField = [self valueForKey:fieldName];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Line" inManagedObjectContext:context];
[request setEntity:entityDescription];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(lineNum = %d)", i];
[request setPredicate:pred];
NSManagedObject *theLine = nil;
NSArray *objects = [context executeFetchRequest:request error:&error];
if (objects == nil) {
NSLog(#"There was an error");
}
if ([objects count] > 0)
theLine = [objects objectAtIndex:0];
else
theLine = [NSEntityDescription insertNewObjectForEntityForName:#"Line" inManagedObjectContext:context];
[theLine setValue:[NSNumber numberWithInt:i] forKey:#"lineNum"];
[theLine setValue:theField.text forKey:#"lineText"];
[request release];
}
[context save:&error];
}
- (void)viewDidUnload
{
self.line1 = nil;
self.line2 = nil;
self.line3 = nil;
self.line4 = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc
{
[line1 release];
[line2 release];
[line1 release];
[line1 release];
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#end
Be sure to change the viewcontroller that gets intialized in the appdelegate with the correct nib. The blank UIView is probably the view created when you started the project.
In your AppDelegate there is a method called applicationdidFinishLaunchingWithOptions, in which something like the following code is located:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[RIViewController alloc] initWithNibName:#"RIViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
In my case I load the RIViewController. By default the nib file has the same name as the controller and is hence named RIViewController aswell.

How to refresh a TableView when data is inserted in the AppDelegate?

To pre-populate my Database for a small Iphone-App I do a check in the persistentStoreCoordinator Method in the AppDelegate if the sqlite-file is already there or not. If not I add some data into a table after the db is created. But the data should not directly shown in the RootViewController but in another TableView which can be accessed by pressing a Option in the RootViewController.
The Problem is that the data are saved but are not shown in the TableView. But if terminate and restart the app the data are there.
I have passed the managedObjectContext from my appDelegate to the the RootViewController and from there to the TableViewController. So the managedObjectContext is the same everywhere.
Here is the Code where I pre-populate the DB (in this example just one sample row):
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"TestDBApp.sqlite"];
NSString *storePath = [storeURL relativePath];
BOOL noDb = false;
NSFileManager *fileManager = [NSFileManager defaultManager];
if( ![fileManager fileExistsAtPath:storePath]) {
noDb = true;
}
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();
}
if( noDb) {
noDb = false;
[self populateDB];
}
return persistentStoreCoordinator_;
}
- (void) populateDB {
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Kunde" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"oxid" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
NSError *error = nil;
if (![aFetchedResultsController performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[self insertNewKunde:aFetchedResultsController];
[self saveContext];
[aFetchedResultsController release];
[sortDescriptors release];
[sortDescriptor release];
[fetchRequest release];
}
- (void)insertNewKunde:(NSFetchedResultsController *)fetchedResultsController {
// Create a new instance of the entity managed by the fetched results controller.
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
// If appropriate, configure the new managed object.
[newManagedObject setValue:[[NSDate date] description] forKey:#"oxid"];
[newManagedObject setValue:#"Max" forKey:#"fname"];
[newManagedObject setValue:#"Mustermann" forKey:#"lname"];
// Save the context.
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
The managedObjectContext is passed from the AppDelegate to the RootViewController as:
- (void)awakeFromNib {
RootViewController *rootViewController = (RootViewController *)[navigationController topViewController];
rootViewController.managedObjectContext = self.managedObjectContext;
}
and to the other TableViewController:
- (void)awakeFromNib {
kundenVC = [[KundenViewController alloc] initWithManagedObjectContext:self.managedObjectContext];
}
Can anyone help me or give a hint?
I also tried to reload the tableView through the viewWillAppear-Method. But no effect.
It is very difficult to guess what is happening but my hunch is that you are not calling self.populateDB until the RootViewController is actually created. This means the RootViewController does not see that data because it is not created.
I could be wrong but I guess that your last line in delegate's awakeFromNib method is eventually calling populateDB through self.managedObjectContext -> persistentStoreCoordinator -> self.populateDB.
Please try to add a line right at the top of awakeFromNib looking like this:
(void)awakeFromNib {
NSManagedObjectContext *context = self.managedObjectContext;
RootViewController *rootViewController = (RootViewController *)[navigationController topViewController];
rootViewController.managedObjectContext = context;}
This way I hope the your problem is solved because self.managedObjectContext will call the getter (- (NSManagedObjectContext)managedObjectContext;) instead of the field. Inside there (if you use the generated code) there is a call to the getter of ** persistentStoreCoordinator** which eventually calls you populateDB method.
In case that does not work go ahead and set a breakpoint inside your populateDB. When the debugger stops you should see at the method call stack where you populateDB is actually called from and that might help to figure out your problem.
-Andy
Well, the important part you left out to answer your question. What is [self saveContext] and how are you displaying the records in your table view.
Because your data is saved I assume that the code given here works. The only guess I can make is to use reset on the NSManagedObjectContext and then refetch.
BTW I like the "insertNewKunde" which seems to be the new German grammar ;-)

iPhone Core Data does not refresh table

I'm trying to write an application with Core Data, and I have been able to successfully read and write to the core data database. However, if I write to the database in one view controller, my other view controllers will not see the change until the app is closed then reopened again. This is really frustrating. I'm not entirely sure how to get the refresh - (void)refreshObject:(NSManagedObject *)object mergeChanges:(BOOL)flag method to work. How do I get a reference to my managed object?
Anyways, here's the code I'm using to read the data back. This is in the viewDidLoad method.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Website" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"siteName" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if(mutableFetchResults == nil) {
//Handle the error
}
[self setNewsTitlesArray:mutableFetchResults];
[mutableFetchResults release];
[request release];
[newsSourcesTableView reloadData];
Thanks for help in advance!
I am not entirely sure what do you intend to do from what I understand you are changing your managed object context in one view controller and you want the result to be visible in other view controllers is this correct?. Anyway a solution for this is to listen for the NSManagedObjectContextDidSaveNotification (which is send when the context is saved) and register as a observer the view controller you want to be afected by the changes:
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:myController selector:#selector(updateTable:) name:NSManagedObjectContextDidSaveNotification object:controller.context];
The updateTable in the myController Controller the selector could look something like this:
- (void)updateTable:(NSNotification *)saveNotification
{
if (fetchedResultsController == nil)
{
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
//Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
}
else
{
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
// Merging changes causes the fetched results controller to update its results
[context mergeChangesFromContextDidSaveNotification:saveNotification];
[self.tableView reloadData];
}
Hope that helps.
-Oscar
Actually, what I found was that I had the table set to load as my view. When I put the table into another view, everything worked fine.