Core Data: setPrimitiveValue:forKey: behaves really weirdly

949 views Asked by At

This is a mystery:

I'm invoking setPrimitiveValue:forKey: on an NSManagedObject. The key is a legit, persistent, modeled attribute of the object. However, setPrimitiveValue:forKey: fails, often setting the value for a different, arbitrary attribute. The docs say this behavior is expected when invoking setPrimitiveValue:forKey: for an unmodeled key. So it seems Core Data thinks the key is unmodeled.

The strange part:

When the key is hardcoded as a string literal, the primitive value is indeed set successfully. It only fails when the key is a variable. The variable I'm using happens to be passed from the keyPath argument of observeValueForKeyPath:ofObject:change:context:

The keyPath variable is the same as the string literal. isEqual: returns true and the hash values are equal. The keyPath variable is of type __NSCFString. Does anyone know why setPrimitiveValue:forKey: would behave any differently? (This behavior is on OS X 10.9.1)


An update with better information:

The misbehaving key traced back to a string loaded from a file on disk. The example below is an isolated case. If the attribute string "mainAttr" is written to disk and read back in, then setPrimitiveValue:forKey: sets the value for the wrong attribute, not "mainAttr".

Core data object:

@interface Boo : NSManagedObject
@property (nonatomic, retain) NSNumber * mainAttr;
@property (nonatomic, retain) NSNumber * attr1;
@property (nonatomic, retain) NSNumber * attr2;
@property (nonatomic, retain) NSNumber * attr3;
@end

-

#import "Boo.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
            NSManagedObjectContext *context = managedObjectContext();
    NSString *key = @"mainAttr";

    // write to disk, read back in
    NSString *path = [@"~/Desktop/test.txt" stringByExpandingTildeInPath];
    [key writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:NULL];
    key = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];

    Boo *boo = [NSEntityDescription insertNewObjectForEntityForName:@"Boo" inManagedObjectContext:context];
    [boo setPrimitiveValue:@(5) forKey:key];

    NSLog(@"Boo: %@", boo);
    }
    return 0;
}
1

There are 1 answers

0
bllakjakk On

You need the below 3 statements to set the value. Try it.

[self willChangeValueForKey:key];
[boo setPrimitiveValue:@(5) forKey:key];
[self didChangeValueForKey:key];