Приложение вылетает при использовании allKeys, потому что там только один объект? - PullRequest
1 голос
/ 09 января 2012

Я не могу понять, почему 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";
            }
        );
    };
};
}

Ответы [ 3 ]

3 голосов
/ 09 января 2012

В первом примере вы перебираете массив словарей, и, следовательно, NSArray *keys = [roster2 allKeys]; вызывается для массива.Однако во втором примере у вас есть только словарь one .Это не массив словарей.Таким образом, ваш цикл for (NSDictionary *roster2 in nextArray) выполняет итерацию по ключам вашего словаря, которые являются просто строками, а не массивами.Следовательно, ошибка.

Прежде всего, ваше именование сбивает с толку.NSDictionary по имени nextArray?Попробуйте это:

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"]];
    }
}
0 голосов
/ 09 января 2012

Сообщение об ошибке содержит все, что вам нужно знать:

[__NSCFString allKeys]: unrecognized selector

Это означает, что вы пытаетесь вызвать метод allKeys в экземпляре NSString.

Давайте посмотрим, где вы вызываете allKeys:

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

roster2 - это экземпляр NSString, а не NSDictionary.Вы ожидаете, что nextArray будет содержать NSDictionary объектов, но вместо этого он содержит NSString объектов.

0 голосов
/ 09 января 2012

Нет, это потому, что NSString не отвечает на allKeys.Журнал консоли говорит вам об этом - вам нужно прочитать его более внимательно.

В списках в стиле NeXT ({}) определяет массив, содержащий словарь.{} определяет просто словарь.То есть это:

{
    "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];
    }
}
...