Note that there are some explanatory texts on larger screens.

plurals
  1. POCore Data Wont Persist Property Updates to Database
    text
    copied!<p>I'm working with a subclass of NSManagedObject. Actually, it inherits from a class that inherits from a class that itself inherits from NSManagedObject (that shouldn't be a problem, right?).</p> <p><strong>The problem</strong></p> <p>After I make changes to the properties of the object, the object remembers the changes for its lifetime, but the changes are never saved to the database. </p> <p><strong>How Do I Know This?</strong></p> <p>I know this because:</p> <ul> <li>when I restart the app, the changes I've made are lost.</li> <li>telling the context to refresh the object – AFTER I've made changes to the object and told the context to save – sets the object's values back to their original state before I made the changes. </li> <li>when running the app in the simulator, I can look at the sqlite database file in the Finder, and it's modified date isn't updated when I attempt to save the context. </li> </ul> <p><em>Nothing is being written to the database!</em></p> <p><strong>Context</strong></p> <p>I'm using the auto-generated delegate methods to create the store coordinator and the context. Then I'm passing the context to the view controllers in their init methods, as recommended in the docs. The store is SQLite.</p> <p>I am able to successfully insert objects into the database and read them. I can even make property changes to the newly inserted object and save it successfully. I simply don't seem to be able to update object properties when the object is pulled back out of the database.</p> <p>The object is fetched from the store via a relationship from another object. After making changes to its properties, I call the context's save method. However, before doing so, I call the object's isUpdated method and the context's hasChanges method, and both return false. Shouldn't they return true since I've just made changes to the object's properties but haven't saved the context?</p> <p><strong>More</strong></p> <p>If I call the object's committedChanges method before saving the context, however, passing in the names of the properties that I've changed, I get back the correct values of the properties. I'm not sure what this means. I would have thought that this means that the object's new property values have been successfully saved, but clearly they are not saved.</p> <p>I know that the result objects is registered with a context. If I call</p> <pre><code>[[result managedObjectContext] refreshObject:result mergeChanges:YES]; </code></pre> <p>the object reverts back to the original property values. This means that the context is there and that it is the same context from which the record was fetched. And it means that the new property values are never written tot he database.</p> <p><strong>Some Code</strong></p> <p>Here's the code where I'm poking around with all of these things. There are other places in my code where I'm making property changes, but the changes are never saved.</p> <pre><code>- (IBAction)statusControlChanged:(UISegmentedControl *)control { WCAAssessmentResult *result = [self currentResult]; /* printing the existing property values */ if (![result.complete boolValue]) NSLog(@"result is in progress!"); else if ([result.passed boolValue]) NSLog(@"result is passed!"); else NSLog(@"result is not passed!"); /* changing the property values */ switch (control.selectedSegmentIndex) { case 0: NSLog(@"setting incomplete"); result.complete = [NSNumber numberWithBool:NO]; break; case 1: NSLog(@"setting passed"); result.passed = [NSNumber numberWithBool:YES]; result.complete = [NSNumber numberWithBool:YES]; break; case 2: NSLog(@"setting failed"); result.passed = [NSNumber numberWithBool:NO]; result.complete = [NSNumber numberWithBool:YES]; break; default: break; } /* this method always returns an empty dictionary */ NSLog(@"%@", [result changedValues]); /* this method returns the values that I just set */ NSLog(@"%@", [result committedValuesForKeys:[NSArray arrayWithObjects:@"complete", @"passed", nil]]); /* isUpdated returns false */ if (![result isUpdated]) { NSLog(@"result is not updated?! WTF!?!?"); } /* hasChanges returns false */ if (![[result managedObjectContext] hasChanges]) { NSLog(@"context has no changes!? WTF!?!?"); } /* saving the context produces no error */ NSError *error = nil; if (![[result managedObjectContext] save:&amp;error]) { NSLog(@"save failed"); NSLog(@"%@",[error description]); } } </code></pre> <p><strong>A Twist</strong></p> <p>If I create a new result object by inserting a new record into the context, I can set that object's properties and they are saved successfully. In the above code, I'm fetching the object as a member of a to-many association from another object. Is that a clue?</p> <p>I'm tearing my hair out over this. What the hell could be going wrong here?</p> <p><strong>What's NOT The Problem</strong></p> <ul> <li>I've logged the object's class, and it is indeed the correct class</li> <li>I've made sure that the managedObjectContext I'm saving is the same as the object's context</li> <li>I haven't made any changes to the auto-generated setter/getter methods of my managed object classes</li> <li>I've tried using the setValue:forKey: method instead of object's properties</li> <li>I've used the <code>-com.apple.CoreData.SQLDebug 1</code> argument to log Core Data SQL, and no SQL is logged when I update and save the object's properties</li> </ul>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload