Note that there are some explanatory texts on larger screens.

plurals
  1. POOver-optimization bug in 10.9 Core Data Entity Description methods?
    primarykey
    data
    text
    <p>When I send -objectForKey: to the dictionary returned by -[NSManagedObjectModel entitiesByName], -objectForKey: returns the expected result if the passed-in key is a literal constant such as @“foo”. But if I instead pass in a local variable whose value is constructed to be equal to @“foo”, -objectForKey: returns nil in Mac OS X 10.9. In Mac OS X 10.8, it returns the expected value, whether the key is a constant or not.</p> <p>The problem is probably due to the fact that, in 10.9, -entitiesByName returns a subclass of NSDictionary called NSKnownKeysDictionary2. In 10.8, it returns NSKnownKeysDictionary1. My guess is that </p> <ul> <li>During optimization, the compiler coalesces any duplicate constant strings into one.</li> <li>NSKnownKeysDictionary2 is optimized based on the assumption that keys are such constants, and thus uses pointer equality instead of -isEquals:.</li> </ul> <p>According to the documentation, <a href="https://developer.apple.com/library/mac/documentation/cocoa/reference/CoreDataFramework/Classes/NSManagedObjectModel_Class/Reference/Reference.html#//apple_ref/occ/instm/NSManagedObjectModel/entitiesByName" rel="nofollow">-[NSManagedObjectModel entitiesByName] returns an NSDictionary</a>, which is in turn <a href="https://developer.apple.com/library/mac/documentation/cocoa/reference/Foundation/Classes/NSDictionary_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSDictionary" rel="nofollow">documented to use -isEquals: to compare keys</a> …</p> <p><em>Within a dictionary, the keys are unique. That is, no two keys in a single dictionary are equal (as determined by isEqual:).</em></p> <p>So I think this is a bug in Mac OS X 10.9. I think that maybe someone didn't notice that -[NSManagedObjectModel entitiesByName] was a public method when they optimized it to return NSKnownKeysDictionary2. Since most developers use constant strings for entity names, this bug slipped all the way through the Developer Previews and no one noticed.</p> <p>Am I wrong, or should I "file a bug"?</p> <p>Thanks,</p> <p>Jerry Krinock</p> <hr> <p>Code demonstrating this (from my project, sorry) is below. It is from my personal “super subclass” of NSManagedObject, which does all of my favorite things that NSManagedObject does not.</p> <p>As you can see from my “First try” in the code, the results of method +[NSEntityDescription entityForName:inManagedObjectContext:] are also affected by this apparent bug. </p> <p>When I run build the app and run in Mac OS X 10.8, it logs</p> <ul> <li>1st try worked for Stark_entity</li> <li>1st try worked for Ixporter_entity</li> </ul> <p>But when I run the same build in 10.9, with the same data, the 1st, 2nd and 3rd tries apparently fail, because it instead logs</p> <ul> <li>4th try worked for Stark_entity</li> <li>4th try worked for Ixporter_entity</li> </ul> <p>Code:</p> <pre><code>// How I like to name my entities… + (NSString*)entityNameForClass:(Class)class { return [NSStringFromClass(class) stringByAppendingString:@"_entity"] ; } + (NSEntityDescription*)entityDescription { // Stuff we'll need NSArray* bundles = [NSArray arrayWithObject:[NSBundle mainBundle]] ; NSManagedObjectModel* mom = [NSManagedObjectModel mergedModelFromBundles:bundles] ; NSString* entityName = [self entityNameForClass:self] ; // See above // What we want NSEntityDescription* entityDescription = nil ; // First try. NSPersistentStoreCoordinator* psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom] ; NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] init] ; [moc setPersistentStoreCoordinator:psc] ; entityDescription = [NSEntityDescription entityForName:entityName inManagedObjectContext:moc] ; [psc release] ; [moc release] ; NSDictionary* entities = [mom entitiesByName] ; NSLog(@"entities is an %@", [entities className]) ; NSLog(@"entityName is an %@", [entityName class]) ; NSLog(@"entities is a dictionary? = %hhd”, [entities isKindOfClass:[NSDictionary class]]) ; if (entityDescription) { NSLog(@"1st try worked for %@", entityName) ; } else { // Second try entityDescription = [entities objectForKey:entityName] ; if (!entityDescription) { // Third try NSString* entityNameCopy = [entityName copy] ; entityDescription = [entities objectForKey:entityNameCopy] ; [entityNameCopy release] ; } if (!entityDescription) { // Fourth try NSSet* candidateEntityNames = [NSSet setWithObjects: @"Stark_entity", @"Ixporter_entity", nil] ; for (NSString* candidate in candidateEntityNames) { if ([entityName isEqualToString:candidate]) { entityDescription = [entities objectForKey:candidate] ; if (entityDescription) { NSLog(@"4th try worked for %@", entityName) ; break ; } } } } } if (!entityDescription) { NSLog(@"Internal Error 561-3831 for %@", entityName) ; } return entityDescription ; } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

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