应用程序在使用allKeys时崩溃,是因为只有一个对象吗



我不明白xcode为什么继续抛出这个错误

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-    
[__NSCFString allKeys]: unrecognized selector sent to instance 0x9367330'

每当我使用这个代码

NSDictionary *nextArray = [_classDictionary 
valueForKeyPath:@"response.page_records.page_record"];
for (NSDictionary *roster2 in nextArray) {
NSArray *keys = [roster2 allKeys];
if ([keys containsObject:@"title"]){
    [pageName addObject:[roster2 objectForKey:@"title"]];
}
if ([keys containsObject:@"id"]) {
[pageID addObject:[roster2 objectForKey:@"id"]];
}
}

在尝试调试它之后,我发现只有当键只有一个对象时才会抛出异常。例如,当"nextArray"是这样时:

 (
 {
    "class_id" = 0001;
    "id" = 1234;
    "title" = "First Page";
},
{
     "class_id" = 0002;
     "id" = 12345;
     "title" = Assignments;
 }
 )

代码运行时没有异常,但当代码只是时

      {
         "class_id" = 0001;
         "id" = 1234;
         "title" = "First Page";
     }

引发了异常。为什么会发生这种情况?即使只有一个对象,关键帧仍然包含对象标题。为什么抛出这个异常还有其他想法吗?这和括号有关吗?(完全猜测)有没有更好的方法来调试真正发生的事情?

编辑:这是_userDictionary。有一个有序的objectforKey:@"title"数组并避免上述错误的最佳方法是什么?

response =     {
    "status" = ok;
    "page_records" =         {
        "page" = 1;
        "page_count" = 1;
        "records_per_page" = 50;
        "total_record_count" = 2;
        "page_record" =             (
                            {
                "class_id" = 0001;
                "id" = 1234;
                "title" = "Test page";
            },
                            {
                "class_id" = 0002;
                "id" = 12345;
                "title" = "testing page 2";
            }
        );
    };
};
}

在第一个例子中,您正在遍历一个字典数组,因此,NSArray *keys = [roster2 allKeys];被调用到一个数组中。然而,在第二个示例中,您只有一个字典。这不是一个字典数组。因此,循环for (NSDictionary *roster2 in nextArray)正在遍历字典的键,这些键只是字符串,而不是数组。因此,出现了错误。

首先,您的命名令人困惑。一个叫nextArrayNSDictionary?试试这个:

id *response = [_classDictionary valueForKeyPath:@"response.page_records.page_record"];  
NSMutableArray *records;  
if ([response isKindOfClass: [NSDictionary class]]) {
    records = [[NSMutableArray alloc] init];
    [records addObject: response];
}
else {
    records = [NSMutableArray arrayWithArray: response];
}
for (NSDictionary *roster2 in records) {
    NSArray *keys = [roster2 allKeys];
    if ([keys containsObject:@"title"]){
        [pageName addObject:[roster2 objectForKey:@"title"]];
    }
    if ([keys containsObject:@"id"]) {
        [pageID addObject:[roster2 objectForKey:@"id"]];
    }
}

错误消息包含您需要知道的所有信息:

[__NSCFString allKeys]: unrecognized selector

这意味着您正试图在NSString的实例上调用方法allKeys

让我们看看您在哪里调用allKeys:

for (NSDictionary *roster2 in nextArray) {
    NSArray *keys = [roster2 allKeys];

roster2是NSString的实例,而不是NSDictionary。您期望nextArray包含NSDictionary对象,但它却包含NSString对象。

不,因为NSString不响应allKeys。控制台日志告诉您这一点——您需要更仔细地阅读它。

在NeXT风格的plists中,({})定义了一个包含字典的数组。{}定义只是一个字典。也就是说,这个:

{
    "class_id" = 0001;
    "id" = 1234;
    "title" = "First Page";
}

在结构上是否相同:

(
    {
        "class_id" = 0001;
        "id" = 1234;
        "title" = "First Page";
    }
)

即使它们包含相同的信息。即使根数组中只有一个元素,您仍然需要告诉plist解析器那里有一个数组,因此您需要包括(),以便逻辑正确处理它。

编辑:考虑到您评论中的信息,解决方案不会那么简单。如果您的源数据是任意的,那么您需要检查数据的类型,看看它是NSArray还是NSDictionary,并对其进行适当的处理。例如:

id myData = [self plistFromArbitrarySource];
if (myData) {
    if ([myData isKindOfClass: [NSArray class]]) {
        for (NSDictionary *dict in myData) {
            [self parseDictionary:dict];
        }
    } else if ([myData isKindOfClass: [NSDictionary class]]) {
        [self parseDictionary:myData];
    }
}