简体   繁体   English

使用ObjectiveC进行JSON解析的弹性

[英]Resilience in JSON parsing with ObjectiveC

A JSON API feed used by our iOS ObjectiveC app is a bit flaky, so sometimes a field is null. 我们的iOS ObjectiveC应用程序使用的JSON API提要有点不稳定,因此有时字段为空。

When parsing JSON we use 解析我们使用的JSON时

NSDictionary *json = [self JSONFromResponseObject:responseObject];

Then try to use the fields with eg 然后尝试使用例如的字段

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

Where sometimes the "name" field will be a null. 有时“名称”字段将为空。 Do we: 我们要不要:

1) Ask the API provider to clean up their flaky API code 1)要求API提供商清理他们的片状API代码

2) Check for null each and every time we try to use something from the json dict 2)每次我们尝试使用json dict中的内容时检查null

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

3) Use try - catch 3)使用try - catch

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

ANSWER: 回答:

Thanks for the answers, below. 谢谢你的答案,如下。 Here is the extension to NSObject I added that allows me to get deeply nested JSON items that may or may not be present. 这是我添加的NSObject的扩展,它允许我获得可能存在或可能不存在的深层嵌套JSON项。

First call with something like 先用类似的东西打电话

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

Here is the code in NSObject+extensions.m 这是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
}

null in a JSON response isn't "flaky", it is absolutely standard. JSON响应中的null不是“片状”,它绝对是标准的。

Even if it was "flaky", any message that you receive from the outside is an attack vector that could allow an attacker to hack into your program, so resilience is required. 即使它是“片状”,您从外部收到的任何消息都是攻击媒介,可能允许攻击者入侵您的程序,因此需要弹性。 Crashing when your receive a null allows a DOS attack against your application. 当您收到null时允许对您的应用程序进行DOS攻击时崩溃。

@try / @catch is awful. @try / @catch很糟糕。 Exceptions are thrown in response to programming errors. 响应编程错误而抛出异常。 You don't catch them, you fix your code. 你没有抓住它们,你修复了你的代码。

How do you fix your code? 你如何修复你的代码? Simple. 简单。 Write a few helper methods in an NSDictionary extension. 在NSDictionary扩展中编写一些帮助方法。

First you don't know that json is a dictionary. 首先你不知道json是一本字典。 So you add an NSDictionary class method where you pass in anything and it returns what you passed if it is a dictionary and nil (with appropriate logging) if it is anything else. 所以你添加一个NSDictionary类方法,你传入任何东西,它返回你传递的内容,如果它是一个字典和nil(有适当的日志),如果它是其他任何东西。

Next you assume that there is a dictionary under the key "name". 接下来,假设键“name”下有一个字典。 So you write an extension "jsonDictionaryForKey" which returns a dictionary if there is one, and nil (with appropriate logging) if it is anything else. 所以你写了一个扩展名“jsonDictionaryForKey”,如果有的话,它返回一个字典,如果是其他的话,则返回nil(有适当的记录)。

And so on. 等等。 Make your JSON parsing bullet proof if you want to call yourself a professional developer. 如果您想称自己为专业开发人员,请使您的JSON解析子弹证明。 For extra bonus points you add a method which will take a dictionary and list all keys that are present that you didn't ask for - so you know if your API is sending things that you don't expect. 要获得额外的奖励积分,您需要添加一个方法,该方法将获取字典并列出您没有要求的所有存在的键 - 因此您知道您的API是否正在发送您不期望的内容。

You can delete all NSNULL values in your JSON object. 您可以删除JSON对象中的所有NSNULL值。 Here is a function I used in my library to git rid of all null values in a JSON object. 是我在我的库中使用的函数,用于删除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;
}

After all null values have been cleared, perhaps the exceptions will gone too. 清除所有空值后,也许异常也会消失。

An approach that's often used is categories similar to these on NSDictionary and NSMutableDictionary , that ignore nil and NSNull . 经常使用的方法是类似于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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM