【问题标题】:Detect Missing JSON Keys With Nested Objects使用嵌套对象检测丢失的 JSON 键
【发布时间】:2013-08-15 16:57:15
【问题描述】:

目前我正在使用仍在开发中的 API。因此,响应中的键仍在变化。我已经成功地能够从 API 检索 JSON 数据并将其解析为 NSDictionary,然后使用此 NSDictionary 将值映射到自定义对象中。我使用的方法如下

-(id)initWithDictionary:(NSDictionary*)dictionary
{
    if(self = [super init]){
        _ID = [dictionary valueForKey:kKEY_ID];
        _name = [dictionary valueForKey:kKEY_NAME];
        _nestedObject = [[NestedObject alloc]initWithDictionary:[dictionary valueForKey:kKEY_NESTED_OBJECT]];
        //etc...
    }
    return self
}

每个嵌套对象也包含相同的解析结构。

这工作正常,除非 API 发生变化。当某些事情发生变化时,所需的值不存在,这会导致意外行为或崩溃。

理想情况下,如果其中一个键发生更改,我想生成一个 NSError ,我可以使用它来打印已更改的值,帮助我更快地找到更改并纠正它。

我目前能想到的唯一替代方法是混乱且无法维护。

-(id)initWithDictionary:(NSDictionary*)dictionary andError:(NSError**)error
{
    if(self = [super init]){

        BOOL _parsedSuccessfully = TRUE;

        if (_parsedSuccessfully) {
             _ID = [dictionary valueForKey: kKEY_ID];

             if (!_ID){
                 _parsedSuccessfully = FALSE;
                 *error = [NSError parsingErrorFromKey: kKEY_ID];
             }
        }

        if (_parsedSuccessfully) {
             _name = [dictionary valueForKey: kKEY_NAME];

             if (!_name){
                 _parsedSuccessfully = FALSE;
                 *error = [NSError parsingErrorFromKey: kKEY_NAME];
             }
        }

        if (_parsedSuccessfully) {
             _nestedObject = [[NestedObject alloc]initWithDictionary:[dictionary valueForKey:kKEY_NESTED_OBJECT]];

             if (!_nestedObject){
                 _parsedSuccessfully = FALSE;
                 *error = [NSError parsingErrorFromKey: kKEY_NESTED_OBJECT];
             }
        }

        //etc...

        if (!_parsedSuccessfully) {
            return nil;
        }
    }
    return self
}

我想知道是否还有其他人有其他更好的方法,最好使用更少的重复。

任何帮助将不胜感激。

【问题讨论】:

    标签: iphone ios objective-c json parsing


    【解决方案1】:

    为您的对象添加一个isValid 方法,该方法可以在任何情况下使用,而不仅仅是在从 JSON 字典初始化时。

    - (BOOL)isValid:(NSError **)error {
    
        #define CHECK_NOT_NULL(x, key) if (!x) { \
            if (error != NULL) \
                *error = [NSError parsingErrorFromKey:key]; \
            return NO; \
        }
    
        #define CHECK_NOT_EMPTY(x, key) if (!x || ![x length]) { \
            if (error != NULL) \
                *error = [NSError parsingErrorFromKey:key]; \
            return NO; \
        }
    
        CHECK_NOT_NULL(_ID, kKEY_ID);
        CHECK_NOT_EMPTY(_name, kKEY_NAME);
        // etc.
    
        return YES;
        #undef CHECK_NOT_NULL
        #undef CHECK_NOT_EMPTY
    }
    

    然后在你的 init 方法中使用它:

    - (id)initWithDictionary:(NSDictionary*)dictionary andError:(NSError**)error
    {
        if (self = [super init]) {
             _ID = [dictionary valueForKey: kKEY_ID];
             _name = [dictionary valueForKey: kKEY_NAME];
             // etc.
    
             if (![self isValid:error]) {
                 self = nil;    // Assuming ARC
             }
        }
        return self;
    }
    

    【讨论】:

    • 这个解决方案似乎正是我想要的。我喜欢它如何优雅地处理解析失败的子对象。而且我还发现您对定义函数的使用非常有趣且可维护。感谢您的帮助!
    • @trojanfoe ...如果需要即时进行任何转换,他可以致电[self setValuesForKeysWithDictionary:dictionary]; 并覆盖setValue:forKey:
    • @trojanfoe 由于您的帖子更新将空检查移到定义函数中,我能够将定义的函数抽象到我的定义文件中,以便可以在每个子对象中重用它们我正在解析。这非常有帮助。
    【解决方案2】:

    如果您创建了一个键数组,那么您可以在循环中运行检查,这样您就只有一个循环副本。

    同样,使用数组,您可以从字典中获取所有键并将它们相互删除。一种方式会给你新的钥匙,另一种方式会给你丢失的钥匙。

    【讨论】:

    • 我真的很喜欢这个主意。但是,我目前正在努力的部分是顶层对象如何知道子对象是否创建失败。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-27
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多