【问题标题】:Resilience in JSON parsing with ObjectiveC使用 Objective C 解析 JSON 的弹性
【发布时间】: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
}

【问题讨论】:

    标签: ios objective-c iphone json


    【解决方案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】:

      一种经常使用的方法是类似于NSDictionaryNSMutableDictionary 上的类别,忽略nilNSNull

      @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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多