【问题标题】:-[NSCFNumber count]: unrecognized selector-[NSCFNumber count]:无法识别的选择器
【发布时间】:2010-12-08 12:28:18
【问题描述】:

我有一些核心数据代码完全遵循 Apple 的 sample code获取满足给定函数的属性值 示例)。我正在使用它来获取字段的最大值,因此我可以在插入该实体类型的下一个对象时递增它。

我根本无法让代码工作,直到我将我的商店类型从 NSXMLStoreType 切换到 NSSQLiteStoreType,然后突然之间一切似乎都正常了。然而,事实并非如此。我注意到它总是会返回相同的值,即使我插入了更高的对象。但是,在我退出并重新打开后(因此数据被持久化并读回),它会随着新的插入而更新。

然后我开始在每次插入后提交和保存。不过,在第一次“自动保存”之后,我收到以下错误(连续两次):

-[NSCFNumber count]:无法识别的选择器发送到实例 0x100506a20

当我执行一次获取请求时会发生这种情况(连续两次):

NSArray *objects = [context executeFetchRequest:request error:&error];

更新

我通过 Zombies 工具运行了我的代码,并且能够查看出现错误的对象。运行malloc 分配它的调用是:-[NSUserDefaults(NSUserDefaults) initWithUser:]。由于我没有设置任何自己的默认值,所以我不知道这可能是什么对象。

更新 2

我在所有代码中搜索了“发布”,并注释掉了静态分析器没有抱怨的每个 releaseautorelease。我仍然得到错误。我什至在我的代码中注释掉最后一个release/autorelease,但仍然得到它。现在我相当确定我自己的代码没有过度发布。

更新 3

This post 似乎有同样的问题,但他的解决方案没有意义。他将结果类型从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;

【问题讨论】:

  • 当你说它完全遵循 Apple 的代码时,你的意思是它实际上是逐字节相同的,还是说你可能在某个时候使用实例变量而不是局部变量?
  • 你能加你的代码吗,你怎么把request粘在一起?
  • 但这不是你的代码。

标签: objective-c cocoa macos core-data nsfetchrequest


【解决方案1】:

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

You can find the OpenRadar entry here

我为这个错误填写了一份副本——我鼓励遇到相同问题的人也这样做,以增加记录(甚至更好,修复)这种烦人行为的可能性。

【讨论】:

  • 这是有用的信息,但正如问题中提到的,我使用的是NSSQLiteStoreType,而不是NSInMemoryStoreType
  • 也许当一些自动保存完成时,NSInMemoryStoreType 被使用。我和你的情况完全一样。有时它会崩溃,有时不会。似乎当程序尝试重新打开已自动保存(顺便说一下!)但未保存的已关闭文档时,它会崩溃。
【解决方案2】:

当您遇到内存管理问题(选择器被发送到错误的实例是内存管理问题的标志)时,您可以做很多事情:

  1. 重新阅读 Cocoa memory management rules 并确保您关注它们。
  2. 运行static analyser。这通常会发现您忽略了内存管理规则的地方。
  3. 尝试使用NSZombieEnabled 了解您是否[以及何时]向未分配的实例发送消息。

【讨论】:

  • 我非常频繁地运行静态分析器,并且 NSZombieEnabled 没有显示任何内容。不过,我可以重新阅读内存管理规则。
  • 当您遇到 Core Data 问题(更改存储类型产生奇怪的错误是 Core Data 问题的标志)时,总有一个千篇一律的答案。
【解决方案3】:

-[NSCFNumber count]: unrecognized selector sent to instance 0x100506a20 表示您正在对 NSCFNumber 对象调用 count,但 NSCFNumber 没有此方法。所以最有可能的计数是发送到一个已释放的 NSArray 或 NSSet 对象。

使用NSZombieEnabled = YES。它可能会告诉你,会发生什么。搜索 SO 以获取有关如何设置它的信息。

【讨论】:

  • NSZombieEnabled 什么也没告诉我。此外,选择器是从某个地方的 API 代码发送的,而不是我写的任何东西(我知道的)。
  • 系统代码很容易将其发送到您的代码过度释放的数组、集合或字典。在过度发布之后,一个新的 NSNumber 将被分配到数组、集合或字典曾经所在的位置。
  • 如果是这种情况,我将如何查找导致问题的对象?有什么仪器或其他可能有帮助的东西吗?
  • 是的,使用带有僵尸选项的分配工具表格工具。也可以考虑试试静态分析器。
  • 当我查看正在接收无法识别的选择器的对象的历史记录(我通过错误中的地址找到)时,它被过度保留,而不是过度释放。在高峰期,它的 RefCt 为 66,而在应用退出时它只下降到 52。
【解决方案4】:

如果绑定设置不正确,也会发生这种情况。例如,如果您将矩阵布尔值绑定到“内容”而不是(或除了)IB 中的“选定标签”,您可能会收到此错误。

如果所有其他方法都失败了,请断开所有绑定并一次重新连接它们,看看哪个是罪魁祸首。

【讨论】:

    【解决方案5】:

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

    【讨论】:

    • 不,毕竟没有用。然而,我在documentation 中发现了这一点,并认为它可能与问题有关,但对 Core Data 来说太新了,无法确定:“如果对象图管理器使用了接收者模型,则此方法会引发异常。”
    • 在完全删除 [request setResultType:NSDictionaryResultType]; 后,我肯定不再收到此错误(不仅仅是替换为 NSManagedObjectResultType,因为您在“更新 3”中输入。但是,返回的值有时不准确。就像有一个滞后:当我反复增加值,保存到新对象,再次获取最大值,重复,有时连续2或3个对象没有增加但有重复。
    【解决方案6】:

    您在路径表达式中使用了关键路径:sortOrder。至少对于 XML-Databases Core-Data 不能处理区分大小写的类型。将路径更改为sortorder(全部小写)

    如果您使用控制器类,您可能会遇到更多问题。

    【讨论】:

    • 感谢您的意见。我不再使用 XML 后备存储,但很高兴知道这一点。
    猜你喜欢
    • 2011-10-16
    • 1970-01-01
    • 2018-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多