Могу ли я заставить AFNetworking автоматически анализировать NULL до нуля?

Мы используем AFNetworking в нашем мобильном приложении, и много раз мы будем возвращать JSON с нулевым значением для некоторых значений.

Мне надоело делать следующее.

if ([json objectForKey:@"nickname"] isKindOfClass:[NSNull class]]) {
    nickname = nil;
} else {
    nickname = [json objectForKey:@"nickname"];
}

Что мы можем сделать, чтобы AFNetworking автоматически устанавливал объекты в nil или числа в 0, если значение равно null в ответе JSON?


person birarda    schedule 22.05.2012    source источник


Ответы (6)


На самом деле это невозможно, так как словарь не может содержать nil в качестве объекта для ключа. Ключ должен быть полностью опущен, чтобы получить желаемое поведение, что само по себе нежелательно.

Предположим, вы не контролируете данные, которые получаете, и не знаете, какие ключи присутствуют в JSON. Если бы вы хотели перечислить их все или отобразить в таблице, а ключи для нулевых объектов были исключены из словаря, вы бы увидели неправильный список.

NSNull — это заполнитель «ничего» для коллекций Cocoa, и именно поэтому он используется в данном случае.

Вы можете упростить набор текста с помощью макроса:

#define nilOrJSONObjectForKey(JSON_, KEY_) [[JSON_ objectForKey:KEY_] isKindOfClass:[NSNull class]] ? nil : [JSON_ objectForKey:KEY_]

nickname = nilOrJSONObjectForKey(json, @"nickname");
person jscs    schedule 22.05.2012
comment
Я думаю, что это, вероятно, то, с чем я пойду, макрос, который я имею в виду. Спасибо! - person birarda; 22.05.2012
comment
На самом деле я не уверен, почему полностью отказаться от ключа - это плохо? Я бы предпочел сделать nickname = [json objectForKey:@"nickname"] и сделать это нулевым, и иметь возможность просто сказать if(!nickname) в другом месте. - person birarda; 22.05.2012
comment
@biarda: Что, если вы хотите запросить у словаря список всех его ключей? Вы получите неправильный ответ — ключ существует в JSON. - person jscs; 22.05.2012
comment
Я не уверен, что мне когда-либо приходилось это делать, или я могу придумать причину, по которой мне нужно это сделать. - person birarda; 22.05.2012
comment
Предположим, вы выводили весь словарь в виде таблицы или просто не знали, какие ключи доступны. - person jscs; 22.05.2012
comment
Для наших целей это относится к ответу API от нашего бэкэнда, чтобы мы знали, что мы ожидаем в словаре. - person birarda; 22.05.2012
comment
Конечно, но во многих других случаях можно получить данные из службы, которую он не контролирует. - person jscs; 22.05.2012
comment
Согласованный. Я думаю, что макрос хорош в этих случаях ... Я найду библиотеку, такую ​​​​как TouchJSON, которую я могу использовать с AFNetworking, которая позволит мне установить все, что возвращает NULL, на nil для этих вызовов API. Спасибо! - person birarda; 22.05.2012
comment
Рад, что смог помочь. Я собираюсь включить эти комментарии в свой ответ, чтобы мы могли их очистить позже. - person jscs; 22.05.2012
comment
Мне пришлось изменить макрос, чтобы он работал правильно: #define nilOrJSONObjectForKey(JSON_, KEY_) [[JSON_ objectForKey:KEY_] isEqual:[NSNull null]] ? ноль: [JSON_ objectForKey:KEY_]; - person JBlake; 14.06.2013

Вы можете установить для флага setRemovesKeysWithNullValues ​​значение YES в сериализаторе ответов AFHTTPSessionManager:

AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithBaseURL:url sessionConfiguration:config];
AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
[serializer setRemovesKeysWithNullValues:YES];
[manager setResponseSerializer:serializer];
person DV_    schedule 13.03.2015
comment
Ваши ответы мне нравятся больше остальных - person Lolloz89; 02.04.2015

Ответ DV_ отлично работает для AFHTTPSessionManager. Но если вы используете AFHTTPRequestOperation вместо менеджера, попробуйте следующее:

AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
serializer.removesKeysWithNullValues = YES;
op.responseSerializer = serializer;
person gavdotnet    schedule 10.04.2015
comment
Работает. Однако я думаю, что вы имели в виду: AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer]; - person o.shnn; 26.05.2015
comment
Да, действительно. Отредактировано. Спасибо - person gavdotnet; 27.05.2015

Существует один красивый кокосовый стручок под названием Minced https://github.com/hyperoslo/Minced, который может делать то, что может помочь вам обработать NULL из ответа JSON. Вместо NULL ставится пустая строка.

person Boris Nikolic    schedule 28.10.2015

Если вы замените стандартную NSJSONSerialization на SBJSON, это решит вашу проблему.

SBJSON делает объекты нулевыми вместо выбора NSJSONSerialization «нулевого»

посмотрите требования к различным анализаторам JSON, которые вы можете использовать. https://github.com/AFNetworking/AFNetworking#requirements

person Farhan Patel    schedule 22.05.2012
comment
Я только что попробовал это, и это не похоже на поведение SBJSON по умолчанию. Если я удаляю оператор управления, чтобы проверить, является ли он нулевым, я получаю эту ошибку [NSNull stringByDecodingHTMLEntities] при попытке установить свойство. - person birarda; 22.05.2012

Вы можете настроить AFNetworking в этой функции. установить любое значение по умолчанию для объектов, которые являются NULL

static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingOptions readingOptions) {
if ([JSONObject isKindOfClass:[NSArray class]]) {
    NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:[(NSArray *)JSONObject count]];
    for (id value in (NSArray *)JSONObject) {
        [mutableArray addObject:AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions)];
    }

    return (readingOptions & NSJSONReadingMutableContainers) ? mutableArray : [NSArray arrayWithArray:mutableArray];
} else if ([JSONObject isKindOfClass:[NSDictionary class]]) {
    NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:JSONObject];
    for (id <NSCopying> key in [(NSDictionary *)JSONObject allKeys]) {
        id value = (NSDictionary *)JSONObject[key];
        if (!value || [value isEqual:[NSNull null]]) {
            // custom code here
            //[mutableDictionary removeObjectForKey:key];
            [mutableDictionary setObject:@"" forKey:key];
        } else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
            mutableDictionary[key] = AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions);
        }
    }

    return (readingOptions & NSJSONReadingMutableContainers) ? mutableDictionary : [NSDictionary dictionaryWithDictionary:mutableDictionary];
}

return JSONObject;

}

person Linh Nguyen    schedule 14.06.2017