Joshcodes
Joshcodes

Reputation: 8871

Core Data boolean key value change not reflected in fetch

Given an NSManagedObject subclass with a boolean property deleted (this is demonstrated in two different ways with code below since both approaches are not working):

[Code Listing 1]

@interface MyManagedObject : NSManagedObject

@property (nonatomic, retain) NSNumber *deleted;
// Or @property (nonatomic) BOOL deleted;

@end

created and inserted into Core Data as follows:

[Code Listing 2]

metadata.deleted = [NSNumber numberWithBool:NO];
// metadata.deleted = NO;

and fetched

[Code Listing 3]

// setup entity description
NSEntityDescription* entityDescription = [self entityDescription];

// setup the sorter
NSSortDescriptor* sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"createdAt" ascending:YES];
NSSortDescriptor* sortDescriptorSection = [[NSSortDescriptor alloc] initWithKey:@"myManagedObject.category.title" ascending:YES];

// Build request
NSFetchRequest* request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
[request setSortDescriptors:[NSArray arrayWithObjects:sortDescriptorSection, sortDescriptor, nil]];
[request setPredicate:[NSPredicate predicateWithFormat:@"deleted == %@", [NSNumber numberWithBool:NO]]];

// Fetch request
NSArray* items = [[self managedObjectContext] executeFetchRequest:request error:nil];

returns one item in the items array as expected. The problem is when deleted is modified:

[Code Listing 4]

MyManagedObject* myManagedObject; // Assume initialized
myManagedObject.deleted = [NSNumber numberWithBool:YES];
// myManagedObject.deleted = YES;

// Printing description of myManagedObject in debugger shows deleted = 0 at this point

[myManagedObject.managedObjectContext save:nil];

// Printing description of myManagedObject in debugger still shows deleted = 0 at this point

BOOL testValue = myManagedObject.deleted;
if (testValue) {
    NSLog(@"value updated"); // This line is executed
}

Re-executing code listing 3 still yields one item in the items array even after a NSFetchResultsController watching the database has fired an update. If the application is terminated and relaunched, re-executing code listing 3 yields no items in the items NSArray.

Upvotes: 0

Views: 1000

Answers (3)

Apollo Grace
Apollo Grace

Reputation: 371

Note that this isn't just a problem with deleted and isDeleted. I wrote a database in which I had a "relationship" property, which was an int16 (choice of several relationship types), but then I also had an "isRelationship" boolean which looked at this property and several others to determine whether the content was about the individual or about a relationship. valueForKey:@"relationship" would return the bool for isRelationship - which meant that it also affected NSPredicate. The following predicate:

NSPredicate *pred = [NSPredicate predicateWithFormat:@"relationship IN %@",
    @[[NSNumber numberWithShort:Relationship_Dating],
      [NSNumber numberWithShort:Relationship_Married]]];

would fail to filter out friend or family relationships because they were all returning 1 from isRelationship instead of the actual relationship value.

Watch out for stupidly "clever" system behavior when "is" booleans are involved.

(I fixed this by changing the "-(bool) isRelationship" method to "-(bool) isRelational".)

Upvotes: 0

Martin R
Martin R

Reputation: 539815

Calling a Core Data property "deleted" conflicts with the isDeleted property of NSManagedObject.

Compare Core Data NSPredicate "deleted == NO" does not work as expected for a similar problem and some experiments.

Btw. calling a property "updated" causes also problems, compare Cannot use a predicate that compares dates in Magical Record.

Upvotes: 2

J2theC
J2theC

Reputation: 4452

You should not be using deleted as a property name for an NSManagedObject subclass.

Also, deleted is an NSNumber, not a BOOL. So, when you are using:

BOOL testValue = myManagedObject.deleted;
if (testValue) {
    NSLog(@"value updated"); // This line is executed
}

You are testing if myManagedObject's deleted property is nil or not. If there is a value (even [NSNumber numberWithBool:YES]), testValue will be true.

On an unrelated note, I also advice to capture and log the error when calling NSManagedObjectContext's save method.

Upvotes: 0

Related Questions