3

当我将 -objectForKey: 发送到 -[NSManagedObjectModel entityByName] 返回的字典时,如果传入的键是 @“foo”之类的文字常量,则 -objectForKey: 返回预期结果。但是,如果我改为传入一个其值构造为等于@“foo”的局部变量,则 -objectForKey: 在 Mac OS X 10.9 中返回 nil。在 Mac OS X 10.8 中,无论键是否为常量,它都会返回预期值。

问题可能是由于在 10.9 中,-entitiesByName 返回一个名为 NSKnownKeysDictionary2 的 NSDictionary 子类。在 10.8 中,它返回 NSKnownKeysDictionary1。我的猜测是

  • 在优化期间,编译器将所有重复的常量字符串合并为一个。
  • NSKnownKeysDictionary2 基于键是此类常量的假设进行了优化,因此使用指针相等而不是 -isEquals:。

根据文档,-[NSManagedObjectModel entityByName] 返回一个 NSDictionary,而这又被记录为使用 -isEquals: 来比较键......</p>

在字典中,键是唯一的。也就是说,单个字典中没有两个键是相等的(由 isEqual: 确定)。

所以我认为这是 Mac OS X 10.9 中的一个错误。我认为也许有人在优化它以返回 NSKnownKeysDictionary2 时没有注意到 -[NSManagedObjectModel entityByName] 是一个公共方法。由于大多数开发人员使用常量字符串作为实体名称,因此这个错误在开发人员预览版中一直流传,没有人注意到。

我错了,还是应该“提交错误”?

谢谢,

杰里·克里诺克


演示这一点的代码(来自我的项目,对不起)如下。它来自我个人的 NSManagedObject 的“超级子类”,它完成了我最喜欢的所有 NSManagedObject 没有的事情。

从我在代码中的“第一次尝试”中可以看出,方法 +[NSEntityDescription entityForName:inManagedObjectContext:] 的结果也受到这个明显错误的影响。

当我运行构建应用程序并在 Mac OS X 10.8 中运行时,它会记录

  • 第一次尝试为 Stark_entity 工作
  • 第一次尝试为 Ixporter_entity

但是当我在 10.9 中使用相同的数据运行相同的构建时,第一次、第二次和第三次尝试显然失败了,因为它改为记录

  • 第四次尝试为 Stark_entity
  • 第四次尝试为 Ixporter_entity 工作

代码:

// 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 ;
}
4

0 回答 0