10.9核心数据实体描述方法中的过度优化错误?

时间:2013-10-28 03:39:54

标签: core-data osx-mavericks

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

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

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

根据文档-[NSManagedObjectModel entitiesByName] returns an NSDictionary,依次为documented to use -isEquals: to compare keys ...

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

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

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

谢谢,

杰瑞克里诺克


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

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

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

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

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

  • 第四次尝试为Stark_entity工作
  • 第4次尝试为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 ;
}

0 个答案:

没有答案