2015-11-25 8 views
1

Канал API JSON, используемый нашим приложением iOS ObjectiveC, немного шелушился, поэтому иногда поле равно null.Устойчивость в JSON-анализе с ObjectiveC

При анализе JSON мы используем

NSDictionary *json = [self JSONFromResponseObject:responseObject]; 

Тогда попробуйте использовать поля с, например,

[widgetIDArray addObject:widget[@"name"][@"id"]]; 

Где иногда поле «имя» будет пустым. Есть ли у нас:

1) Попросите поставщика API, чтобы очистить их слоеное код API

2) Проверьте нуль каждый раз, когда мы пытаемся использовать что-то из JSon Словаре

if (![widget[@"name"] isKindOfClass:[NSNull class]]) 

3) Использование попробовать - поймать

@try { 
     [widgetIDArray addObject:widget[@"name"][@"id"]]; 
    } 
@catch (NSException *exception) 
    { 
    NSLog(@"Exception %@",exception); 
    } 

оТВЕТ:

спасибо за ответы, ниже. Вот добавление к NSObject, которое я добавил, что позволяет мне получать глубоко вложенные элементы JSON, которые могут или не могут присутствовать.

Первый вызов с чем-то вроде

self.item_logo = [self valueFromJSONWithKeyArray:event withKeyArray:@[@"categories",@"bikes",@"wheels",@"model",@"badge_uri"]]; 

Вот код в NSObject + extensions.m

- (id) valueFromJSONWithKeyArray:(id)json withKeyArray:(NSArray *)keyArray 
{ 
    for (NSString * keyString in keyArray) 
    { 
     if ([json[keyString] isKindOfClass:[NSObject class]]) 
     { 
      json = json[keyString]; // go down a level 
     } 
     else 
     { 
      return nil; // we didn't find this key 
     } 
    } 
    return json; // We successfully found all the keys, return the object 
} 

ответ

2

нуль в ответ JSON не "слоеный", это абсолютно стандартно.

Даже если это было «flaky», любое сообщение, которое вы получаете снаружи, представляет собой вектор атаки, который может позволить злоумышленнику взломать вашу программу, поэтому необходима устойчивость. Сбой при получении null позволяет атаковать DOS против вашего приложения.

@try/@catch ужасно. Исключения выбрасываются в ответ на ошибки программирования. Вы их не поймаете, вы исправляете свой код.

Как вы исправите свой код? Просто. Напишите несколько вспомогательных методов в расширении NSDictionary.

Сначала вы не знаете, что json - это словарь. Таким образом, вы добавляете метод класса NSDictionary, в котором вы передаете что-либо, и он возвращает то, что вы передали, если это словарь и nil (с соответствующим протоколированием), если это что-то еще.

Далее вы предполагаете, что есть словарь под ключом «имя». Таким образом, вы пишете расширение «jsonDictionaryForKey», которое возвращает словарь, если он есть, и nil (с соответствующим протоколированием), если это что-то еще.

И так далее. Сделайте свой JSON синтаксический анализ, если вы хотите назвать себя профессиональным разработчиком. Для дополнительных бонусных очков вы добавляете метод, который будет принимать словарь и список всех присутствующих ключей, которые вы не запрашивали, - поэтому вы знаете, отправляет ли ваш API то, чего вы не ожидаете.

+0

Благодаря gnash, я расширил свой NSDictionary с помощью ключа ValueFromDict: (NSString *). Он возвращает false, если NULL или объект. –

+0

Итак, он будет разбиваться позже, если вместо строки будет число? Если предполагается, что возвращаются только строки, то зачем вызывать его valueFromDict, а не stringFromDict? Почему «FromDict», если он находится в расширении NSDictionary? Нет смысла говорить «FromDict», особенно не «FromDict», за которым следует ключ? – gnasher729

1

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

id BWJSONObjectByRemovingKeysWithNullValues(id json, NSJSONReadingOptions options) { 
    if ([json isKindOfClass:[NSArray class]]) { 
     NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:[(NSArray *)json count]]; 
     for (id value in (NSArray *)json) { 
      [mutableArray addObject:BWJSONObjectByRemovingKeysWithNullValues(value, options)]; 
     } 

     return (options & NSJSONReadingMutableContainers) ? mutableArray : [NSArray arrayWithArray:mutableArray]; 
    } else if ([json isKindOfClass:[NSDictionary class]]) { 
     NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:json]; 
     for (id<NSCopying> key in [(NSDictionary *)json allKeys]) { 
      id value = [(NSDictionary *)json objectForKey:key]; 

      if (isNullValue(value)) { 
       [mutableDictionary removeObjectForKey:key]; 
      } else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) { 
       [mutableDictionary setObject:BWJSONObjectByRemovingKeysWithNullValues(value, options) forKey:key]; 
      } 
     } 

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

    return json; 
} 

После того, как все нулевые значения были очищены, возможно, исключения также исчезнут.

0

подход, который часто используется категории, подобные этим на NSDictionary и NSMutableDictionary, которые игнорируют nil и NSNull.

@interface NSDictionary (nullnilsafe) 
- (ObjectType)nullnilsafe_objectForKey:(KeyType)aKey; 
@end  

@implementation NSDictionary 

- (ObjectType)nullnilsafe_objectForKey:(KeyType)aKey 
{ 
    id obj = [self objectForKey:aKey]; 
    if (obj && ![obj isKindOfClass:[NSNull class]]){ 
     return obj; 
    } 
    return nil; 
} 

@end 

@interface NSMutalbeDictionary (nullnilsafe) 
- (void)nullnilsafe_setObject:(ObjectType)anObject forKey:(id<NSCopying>)aKey; 
@end  

@implementation NSMutalbeDictionary 
- (void)nullnilsafe_setObject:(ObjectType)anObject forKey:(id<NSCopying>)aKey 
{ 
    if (anObject && aKey && ![anObject isKindOfClass:[NSNull class]]){ 
     [self setObject:anObject forKey:aKey]; 
    } 
} 

@end 
Смежные вопросы