-[NSCFNumber count]: 未识别的选择器

4
我有一些遵循苹果官方的示例代码(获取满足给定函数的属性值)的Core Data代码。我使用它来获取字段的最大值,以便在插入下一个相同实体类型的对象时将其递增。
在我的存储类型从NSXMLStoreType切换到NSSQLiteStoreType后,我才能让代码正常工作,但是它总是返回相同的值,即使我插入了更高的值。但是,在退出并重新打开应用程序后,它将使用新的插入进行更新。
因此,我开始在每次插入后提交和保存数据。但是,在第一次“自动保存”后,我会收到以下错误消息(连续两次): -[NSCFNumber count]: unrecognized selector sent to instance 0x100506a20 这个错误发生在我执行一次获取请求时。
NSArray *objects = [context executeFetchRequest:request error:&error];

更新

我使用了Zombies工具检测我的代码,并查看了产生错误的对象。调用malloc进行分配的方法是:-[NSUserDefaults(NSUserDefaults) initWithUser:]。由于我没有设置自己的默认值,所以我不知道这可能是什么对象。

更新2

我在我的所有代码中搜索了"release"并注释掉了每一个静态分析器没有抱怨的releaseautorelease。我仍然得到错误。我甚至评论掉了我代码中的每一个release/autorelease,但仍然得到相同的错误。现在我相当确定我的代码没有过度释放。

更新3

此帖子似乎遇到了相同的问题,但他的解决方案并不合理。他将结果类型从NSDictionaryResultType更改为NSManagedObjectResultType,这会产生错误的结果。它返回我的实体类中的每个对象,而不是我正在寻找的单个值(max)。

以下是堆栈跟踪的最高级别(当我在异常上中断时,第一次出现):

#0  0x7fff802e00da in objc_exception_throw
#1  0x7fff837d6110 in -[NSObject(NSObject) doesNotRecognizeSelector:]
#2  0x7fff8374e91f in ___forwarding___
#3  0x7fff8374aa68 in __forwarding_prep_0___
#4  0x7fff801ef636 in +[_NSPredicateUtilities max:]
#5  0x7fff800d4a22 in -[NSFunctionExpression expressionValueWithObject:context:]
#6  0x7fff865f2e21 in -[NSMappedObjectStore executeFetchRequest:withContext:]
#7  0x7fff865f2580 in -[NSMappedObjectStore executeRequest:withContext:]

我在网上的许多论坛上看到了这个问题,但是没有人提供可行的解决方案。应广大用户要求,我在下面添加了我的代码。稍微解释一下,我的实体名称是 Box,我试图获取其值的属性是“sortOrder”,一个 Int 32 属性。

NSManagedObjectContext *context = [MyLibrary managedObjectContext];

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Box"
                               inManagedObjectContext:context]];

// Specify that the request should return dictionaries.
[request setResultType:NSDictionaryResultType];

// Create an expression for the key path.
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"sortOrder"];

// Create an expression to represent the function you want to apply
NSExpression *expression = [NSExpression expressionForFunction:@"max:"
                                                     arguments:[NSArray arrayWithObject:keyPathExpression]];

// Create an expression description using the minExpression and returning a date.
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];

// The name is the key that will be used in the dictionary for the return value.
[expressionDescription setName:@"maxSort"];
[expressionDescription setExpression:expression];
[expressionDescription setExpressionResultType:NSInteger32AttributeType];

// Set the request's properties to fetch just the property represented by the expressions.
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];

// Execute the fetch.
NSError *error;
NSNumber *requestedValue = nil;
NSArray *objects = [context executeFetchRequest:request error:&error];
NSLog( @"objects: %@", objects );
if (objects != nil && [objects count] > 0) {
    requestedValue = [[objects objectAtIndex:0] valueForKey:@"maxSort"];
} else {
    [[NSApplication sharedApplication] presentError:error];
}

[expressionDescription release];
[request release];

NSLog( @"Max Sort Order: %@", requestedValue );
return requestedValue;

当你说它严格遵循苹果的代码时,你是指它字节对字节地完全相同,还是可能在某些时候使用实例变量而不是局部变量? - Chuck
你能添加你的代码吗?你是如何组合“request”的? - vikingosegundo
但那不是你的代码。 - vikingosegundo
6个回答

12

显然,这是一个已知的错误,在使用NSInMemoryStoreType数据存储时会出现。使用NSSQLiteStoreType似乎可以正常工作。

您可以在此处找到OpenRadar条目

我为这个bug填了一个重复的报告——我鼓励遇到相同问题的人做同样的事情,增加这种恼人行为得到记录(甚至更好地被修复)的可能性。


这是有用的信息,但正如问题中提到的那样,我正在使用NSSQLiteStoreType而不是NSInMemoryStoreType - Dov
也许在某些自动保存完成时,会使用NSInMemoryStoreType。我和你的情况完全一样。有时会崩溃,有时不会。似乎当程序尝试重新打开已自动保存(顺便提一下!)但未保存的关闭文档时,它会崩溃。 - Colas

3
当你遇到内存管理问题(发送给错误实例的选择器是内存管理问题的迹象),有几件事情可以做:
  1. 重新阅读Cocoa的内存管理规则,确保你正在遵循它们。
  2. 运行静态分析工具。这通常会发现你忽略了内存管理规则的地方。
  3. 尝试使用NSZombieEnabled查找是否[以及何时]向未分配的实例发送消息。

我经常运行静态分析器,但NSZombieEnabled没有显示任何内容。不过我可以重新阅读内存管理规则。 - Dov
当你遇到Core Data问题时(更改存储类型会导致奇怪的错误,这是Core Data问题的迹象),总有一个标准答案。 - Léo Natan

1

-[NSCFNumber count]: 无法识别的选择器发送到实例0x100506a20 的意思是,你正在对一个 NSCFNumber 对象调用 count 方法,但是 NSCFNumber 并没有这个方法。所以很可能 count 被发送到了一个已释放的 NSArray 或 NSSet 对象。

使用 NSZombieEnabled = YES。它可能会告诉你发生了什么。在 SO 上搜索如何设置它的信息。


NSZombieEnabled 对我来说没有提供任何信息。而且,选择器是从 API 代码的某个地方发送的,而不是我编写的任何内容(至少我不知道)。 - Dov
系统代码可能会将其发送到由您的代码过度释放的数组、集合或字典中。在过度释放之后,一个新的NSNumber被分配到了原来数组、集合或字典所在的位置。 - Jon Hess
如果是这样,我该如何找出导致问题的对象?有什么工具或仪器可以帮助吗? - Dov
是的,请使用带有僵尸选项的分配工具表单。同时考虑尝试静态分析器。 - Jon Hess
当我查看接收未识别选择器的对象的历史记录时(通过错误中的地址找到它),它被过度保留了,而不是过度释放。在其峰值时,它的引用计数为66,在应用程序退出时仅降至52. - Dov

1
这也可能发生在绑定设置不正确的情况下。例如,如果您将矩阵布尔值绑定到IB中的“内容”而不是(或除了)“选定标签”,则可能会出现此错误。
如果所有其他方法都失败了,请断开所有绑定,然后逐个重新连接它们,以查看哪一个是罪魁祸首。

0

在使用完全相同的示例代码遇到完全相同的问题后,在我加入[request release]之后,它最终为我工作了。


不,最终它没有起作用。然而,我在文档中找到了这个,并认为它可能与问题有关,但我对Core Data还太新,不能确定:“如果接收者的模型已被对象图管理器使用,则此方法会引发异常。” - stifin
在完全删除[request setResultType:NSDictionaryResultType];(而不仅仅是像您在“更新3”中所做的那样替换为NSManagedObjectResultType)后,我确实停止了收到此错误。但是,返回的值有时不准确。就像有一个滞后:当我重复增加值,保存到新对象,再次获取最大值,重复时,有时连续2或3个对象没有被增加,但有重复项。 - stifin

0

您正在使用键路径:sortOrder在您的路径表达式中。至少对于XML数据库,Core-Data无法处理区分大小写的类型。请将您的路径更改为sortorder(全部小写)

如果您正在使用控制器类,您可能会遇到进一步的问题。


感谢您的输入。我不再使用XML后备存储,但这很有用。 - Dov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接