0

I have check the following Q&A and while the solutions are much the same the issue remains for me remains: Saving an updated Core Data instance

Update/Edit coreData managed object

How to update existing object in Core Data?

I have a log in/log out feature in my app.

The Core Data entity "NewLog" has the following attributes

String loginTime
String logoutTime
String loginStatus
String name

When I login it creates a new object in the core data. When I log out I have the object update.The issue is when I logout it updates the existing object but creates a new object also.

Here is my "save" code from my super class so that I don't have to continuously rewrite it and risk errors in my classes:

- (void) saveAndDismiss{

    NSError * error = nil;
    if ([self.managedObjectContext hasChanges]){
        if (![self.managedObjectContext save: &error]){
            NSLog(@"Save Failed: %@", [error localizedDescription]);
        }
        else {
            NSLog(@"Save Successful");
        }
    }

    [self dismissViewControllerAnimated:YES completion:nil];

}

In my loginViewController implementation file to update the "loginStatus" and "logoutTime":

- (IBAction)logOutButton:(id)sender {

    //access the managed object context and create a shortcut name
    NSManagedObjectContext *context = [self managedObjectContext];

    //refer to the entity in the core data
    NSEntityDescription *entity = [NSEntityDescription entityForName: @"NewLog" inManagedObjectContext:context];

    //create a request
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity: entity];

    // Results should be in descending order of loginTime.
    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"loginTime" ascending:NO];
    [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

    //create an array of results
    NSArray *results = [context executeFetchRequest:request error:NULL];
    NewLog *latestEntity = [results objectAtIndex:0];

    //refer to the specific value that I wish to change
    NSString * statusOfLogin = latestEntity.loginStatus;

    //if the loginStatus in my app is currently YES
    if ([statusOfLogin isEqual:@"YES"]){

        //create a date formatter
        NSDateFormatter *dateformatter=[[NSDateFormatter alloc]init];

        //format as such
        [dateformatter setDateFormat:@"dd MMM yyyy , HH:mm:ss"];

        //convert to a string
        NSString *dateInStringFormated=[dateformatter stringFromDate:[NSDate date]];

        //hide logout button and display login button
        _logOutButton.alpha = 0.0;
        _loginButtonStatus.alpha = 1.0;

        //status declared as String in .h file
        status = @"NO";

        //update the object found in "latestEntity"
        latestEntity.logoutTime = dateInStringFormated;
        //set the login status to be NO
        latestEntity.loginStatus = status;

        //BOOL declared in the .h file
        logStatus = false;


        self.loginLabel.text = @"Logged Out";
        self.dateLabel.text = dateInStringFormated;

        [super saveAndDismiss];

    }

}

When I save the updated data it creates a new object containing only the logoutTime and loginStatus.

Is there a solution to stop the new object being created?

Thanks

EDIT

I know that it is creating a new object the following ways: 1. The SQL file displays the new object with the content stated above - logoutTime and loginStatus 2. The tableview displays the new object and in the detail view for it displays the two items.

Checking the area it's coming from is my segue:

//prepare for segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{

    //first check whether the segue is equal to our transition name
    if([[segue identifier]isEqualToString:@"loginSegue"])
    {
        //tell the segue where to go
        UINavigationController *navigationController = segue.destinationViewController;

        //create reference to view controller
        LoginViewController *loginVC= (LoginViewController*) navigationController.topViewController;

        //create the new object
        NewLog *addLogDetails = [NSEntityDescription insertNewObjectForEntityForName:@"NewLog" inManagedObjectContext: [self managedObjectContext]];

        loginVC.logEntry = addLogDetails;
    }
}

I know why it's creating a new object but how do I prevent this from happening while remaining able to save?

Community
  • 1
  • 1
App Dev Guy
  • 5,396
  • 4
  • 31
  • 54

1 Answers1

1

Nothing in the code in your question is creating a new managed object, so either the problem is elsewhere in your code or you're mistaken that an extra object is being created - you don't say how you have come to this conclusion.

To identify the problem, implement awakeFromInsert on your NewLog object and add a breakpoint. This will be hit every time one of these objects is added, you can then examine the stack trace to find out where the object is being added from.

UPDATE

OK, having done that, you see that you're making a new entity every time the segue is performed. Don't do that. You need to perform a fetch to find the existing login object, and only if there isn't one, or the existing one isn't suitable, create a new one.

If you do a fetch and there's nothing in the array, objectAtIndex:0 will crash. Use firstObject instead and check if the result of that is nil.

jrturton
  • 118,105
  • 32
  • 252
  • 268
  • I know it's creating a new object because I check the SQL file each time I run and test and the tableview also displays the new object as well as the detail view displaying the details as I mention: "When I save the updated data it creates a new object containing only the logoutTime and loginStatus.". I wouldn't have posted this question otherwise. I will try your suggestion of using the awakeFromInsert though. – App Dev Guy Oct 01 '14 at 07:36
  • fetch and check the the count sql file if not your ref point while using core data – amar Oct 01 '14 at 07:47
  • Found that the segue was the issue in my next view controllers class. I know why it's creating a new object now however how can I prevent it while still being able to save the updated information? – App Dev Guy Oct 01 '14 at 08:11
  • Do you have some code that I could try for this at all? I have tried my way which was working fine while I had objects in core data however testing without any objects throws the error message because "objectsAtIndex: 0" is no longer correct. I have tried "if([statusOfLogin isEqual:@"NO"] || latestEntity == nil)" however this is still throwing errors with the same issue that the index is referencing 0. – App Dev Guy Oct 01 '14 at 11:00
  • Also, not the only code I have tried, thought I should make that clear. Always the same message, which makes sense that I am referencing objectAtIndex: 0, however when I am not directly referencing, I don't know why it's throwing errors. – App Dev Guy Oct 01 '14 at 11:08
  • 1
    If there's nothing in the array, objectAtIndex:0 will crash. Use `firstObject` instead and check if the result of that is nil – jrturton Oct 01 '14 at 11:56
  • @jrturton Throw that in your answer mate, I will give it the vote :-) Works perfect now. Thanks for your patience and your help. – App Dev Guy Oct 02 '14 at 01:20