使用 Objective C 解析 JSON 的弹性
Posted
技术标签:
【中文标题】使用 Objective C 解析 JSON 的弹性【英文标题】:Resilience in JSON parsing with ObjectiveC 【发布时间】:2015-11-25 08:52:25 【问题描述】:我们的 ios ObjectiveC 应用使用的 JSON API 提要有点不稳定,因此有时字段为空。
我们在解析 JSON 时使用
NSDictionary *json = [self JSONFromResponseObject:responseObject];
然后尝试使用带有例如的字段
[widgetIDArray addObject:widget[@"name"][@"id"]];
有时“名称”字段为空。我们:
1) 要求 API 提供者清理其易碎的 API 代码
2) 每次我们尝试使用 json dict 中的内容时检查 null
if ( ![widget[@"name"] isKindOfClass:[NSNull class]] )
3) 使用 try-catch
@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
【问题讨论】:
【参考方案1】:JSON 响应中的 null 不是“不稳定的”,它绝对是标准的。
即使它“不稳定”,您从外部收到的任何消息都是攻击媒介,可能允许攻击者侵入您的程序,因此需要恢复能力。当您收到 null 时崩溃允许对您的应用程序进行 DOS 攻击。
@try / @catch 很糟糕。为响应编程错误而引发异常。你没有抓住他们,你修复了你的代码。
您如何修复您的代码?简单的。在 NSDictionary 扩展中编写一些辅助方法。
首先你不知道 json 是一个字典。因此,您添加一个 NSDictionary 类方法,您可以在其中传递任何内容,如果它是字典,则返回您传递的内容,如果是其他任何内容,则返回 nil(带有适当的日志记录)。
接下来,您假设在“名称”键下有一个字典。因此,您编写了一个扩展名“jsonDictionaryForKey”,如果有则返回字典,如果有则返回 nil(带有适当的日志记录)。
等等。如果您想称自己为专业开发人员,请制作您的 JSON 解析防弹。对于额外的奖励积分,您添加一个方法,该方法将获取字典并列出您没有要求的所有存在的键 - 这样您就知道您的 API 是否正在发送您不期望的东西。
【讨论】:
谢谢 gnash,我用 valueFromDict:(NSString*) 键助手扩展了我的 NSDictionary。如果为 NULL 或对象,则返回 false。 所以后面如果有数字而不是字符串会崩溃?如果它应该只返回字符串,为什么称它为 valueFromDict 而不是 stringFromDict?如果它在 NSDictionary 的扩展中,为什么是“FromDict”?没有必要说“FromDict”,尤其是“FromDict”后跟一个键?【参考方案2】:您可以删除 JSON 对象中的所有 NSNULL
值。 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;
在所有空值都被清除之后,也许异常也会消失。
【讨论】:
【参考方案3】:一种经常使用的方法是类似于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
【讨论】:
以上是关于使用 Objective C 解析 JSON 的弹性的主要内容,如果未能解决你的问题,请参考以下文章