递归地从JSON结构中删除null [英] Removing nulls from a JSON structure recursively

查看:135
本文介绍了递归地从JSON结构中删除null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经常发现需要将由NSJSONSerialization创建的数据结构缓存到磁盘,并且由于-writeToFile如果存在空值而失败,因此我需要一种在结构未知时起作用的修复程序. 这样行之有效,并且由于不枚举NSMutableDictionary本身的实例,因此允许直接突变,但是感觉有点hacky.

I'm frequently finding the need to cache data structures created by NSJSONSerialization to disk and as -writeToFile fails if there are nulls, I need a fix that works when the structure is unknown. This works, and direct mutation is allowed as the instances of NSMutableDictionary themselves are not being enumerated, but it feels a bit hacky.

这完全好吗,还是绝对有必要重新创建一棵新树并将其返回?

Is this totally fine or is it absolutely necessary to recreate a new tree and return that?

- (void) removeNullsFromJSONTree:(id) branch
{
    if ([branch isKindOfClass:[NSMutableArray class]])
    {
        //Keep drilling to find the leaf dictionaries
        for (id childBranch in branch)
        {
            [self removeNullsFromJSONTree:childBranch];
        }
    }
    else if ([branch isKindOfClass:[NSMutableDictionary class]])
    {
        const id nul = [NSNull null];
        const NSString *empty = @"";
        for(NSString *key in [branch allKeys])
        {
            const id object = [branch objectForKey:key];
            if(object == nul)
            {
                [branch setObject:empty forKey:key];
            }
        }
    }
}

推荐答案

您的一般方法没有错.由于NSNull是单例,因此可以通过指针比较来查找它.

There's nothing wrong with your general approach. Since NSNull is a singleton, it's fine to look for it by pointer comparison.

但是,您不会重复使用字典中的值.通常,这些值可能是数组或字典本身.也许在您的特定情况下,您知道并非如此.但是如果可能的话,您需要对字典中的每个值执行removeNullsFromJSONTree:.

However, you're not recursing on the values in your dictionary. In general, those values might be arrays or dictionaries themselves. Perhaps in your specific case you know they're not. But if they could be, you need to perform removeNullsFromJSONTree: on each value in the dictionary.

您也不要在数组中查找NSNull.你应该?处理起来很简单:

You also don't look for NSNull in an array. Should you? It's trivial to handle:

[branch removeObject:[NSNull null]];

removeObject:方法删除该参数的所有实例.

The removeObject: method removes all instances of the argument.

我个人不喜欢显式地测试对象类,因为我可以使用类别让消息发送系统为我做这些事情.因此,我可以这样在NSObject上定义一个类别:

Personally I don't like testing object classes explicitly when I can use categories to let the message sending system do it for me. So instead I might define a category on NSObject like this:

// NSObject+KezRemoveNulls.h

@interface NSObject (KezRemoveNulls)

- (void)Kez_removeNulls;

@end

我会为NSObject写一个默认的空操作实现,并为NSMutableArrayNSMutableDictionary覆盖它:

I would write a default do-nothing implementation for NSObject, and override it for NSMutableArray and NSMutableDictionary:

// NSObject+KezRemoveNulls.m

#import "NSObject+KezRemoveNulls.h"

@implementation NSObject (KezRemoveNulls)

- (void)Kez_removeNulls {
    // nothing to do
}

@end

@implementation NSMutableArray (KezRemoveNulls)

- (void)Kez_removeNulls {
    [self removeObject:[NSNull null]];
    for (NSObject *child in self) {
        [child Kez_removeNulls];
    }
}

@end

@implementation NSMutableDictionary (KezRemoveNulls)

- (void)Kez_removeNulls {
    NSNull *null = [NSNull null];
    for (NSObject *key in self.allKeys) {
        NSObject *value = self[key];
        if (value == null) {
            [self removeObjectForKey:key];
        } else {
            [value Kez_removeNulls];
        }
    }
}

@end

请注意,所有实施代码仍位于一个文件中.

Note that all of the implementation code is still in one file.

现在我可以这样说:

id rootObject = [NSJSONSerialization JSONObjectWithData:...];
[rootObject Kez_removeNulls];

这篇关于递归地从JSON结构中删除null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆