从JSON结构递归删除空(Removing nulls from a JSON structure

2019-09-01 13:51发布

我经常发现有必要来缓存创建的数据结构NSJSONSerialization到磁盘和-writeToFile如果有空失败,我需要在结构未知一个可行的修复。 这工作,并直接突变被允许以自己没有被列举的NSMutableDictionary的实例,但感觉有点哈克。

这是完全正常或者是绝对有必要重新创建一个新树,并返回?

- (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];
            }
        }
    }
}

Answer 1:

这没有什么不对您的一般方法。 由于NSNull是一个单,它的罚款由指针比较来寻找它。

但是,你没有递归在你的字典中的值。 一般情况下,这些值可能是数组或字典本身。 也许在你的具体情况下,你知道他们不是。 但是,如果他们可以,你需要执行removeNullsFromJSONTree:在字典中的每个值。

你也不用找NSNull在数组中。 你应该? 这是微不足道的处理:

[branch removeObject:[NSNull null]];

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

我个人不喜欢的测试对象类明确的时候,我可以使用类别来让消息发送系统为我做的。 所以不是我可以定义一个类NSObject是这样的:

// NSObject+KezRemoveNulls.h

@interface NSObject (KezRemoveNulls)

- (void)Kez_removeNulls;

@end

我会写一个默认什么也不做执行NSObject ,并覆盖它NSMutableArrayNSMutableDictionary

// 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

注意,所有的实现代码仍然是在一个文件中。

现在,我可以这样说:

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


Answer 2:

下面是我用清理我的JSON调用的代码,似乎运作良好,但是,因为有参与我真的只使用它的情况下,我不能做服务器上的空处理一些处理开销。 NSNull崩溃是距离远,我们最大的应用程序崩溃的问题。

+ (id)cleanJsonToObject:(id)data {
    NSError* error;
    if (data == (id)[NSNull null]){
        return [[NSObject alloc] init];
    }
    id jsonObject;
    if ([data isKindOfClass:[NSData class]]){
        jsonObject = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
    } else {
        jsonObject = data;
    }
    if ([jsonObject isKindOfClass:[NSArray class]]) {
        NSMutableArray *array = [jsonObject mutableCopy];
        for (int i = array.count-1; i >= 0; i--) {
            id a = array[i];
            if (a == (id)[NSNull null]){
                [array removeObjectAtIndex:i];
            } else {
                array[i] = [self cleanJsonToObject:a];
            }
        }
        return array;
    } else if ([jsonObject isKindOfClass:[NSDictionary class]]) {
        NSMutableDictionary *dictionary = [jsonObject mutableCopy];
        for(NSString *key in [dictionary allKeys]) {
            id d = dictionary[key];
            if (d == (id)[NSNull null]){
                dictionary[key] = @"";
            } else {
                dictionary[key] = [self cleanJsonToObject:d];
            }
        }
        return dictionary;
    } else {
        return jsonObject;
    }
}

您可以通过将通过NSURLConnection的检索NSData的调用它。

NSArray *uableData = [utility cleanJsonToObject:data];

要么

NSDictionary *uableData = [utility cleanJsonToObject:data];


Answer 3:

斯威夫特4版@Travis M.的回答;

class func removeNullFromJSONData(_ JSONData: Any) -> Any {
    if JSONData as? NSNull != nil {
        return JSONData
    }

    var JSONObject: Any!

    if JSONData as? NSData != nil {
        JSONObject = try! JSONSerialization.data(withJSONObject: JSONData, options: JSONSerialization.WritingOptions.prettyPrinted)
    }
    else {
        JSONObject = JSONData
    }

    if JSONObject as? NSArray != nil {
        let mutableArray: NSMutableArray = NSMutableArray(array: JSONObject as! [Any], copyItems: true)
        let indexesToRemove: NSMutableIndexSet = NSMutableIndexSet()

        for index in 0 ..< mutableArray.count {
            let indexObject: Any = mutableArray[index]

            if indexObject as? NSNull != nil {
                indexesToRemove.add(index)
            }
            else {
                mutableArray.replaceObject(at: index, with: removeNullFromJSONData(indexObject))
            }
        }

        mutableArray.removeObjects(at: indexesToRemove as IndexSet)

        return mutableArray;
    }
    else if JSONObject as? NSDictionary != nil {
        let mutableDictionary: NSMutableDictionary = NSMutableDictionary(dictionary: JSONObject as! [AnyHashable : Any], copyItems: true)

        for key in mutableDictionary.allKeys {
            let indexObject: Any = mutableDictionary[key] as Any

            if indexObject as? NSNull != nil {
                mutableDictionary.removeObject(forKey: key)
            }
            else {
                mutableDictionary.setObject(removeNullFromJSONData(indexObject), forKey: key as! NSCopying)
            }
        }

        return mutableDictionary
    }
    else {
        return JSONObject
    }
}


Answer 4:

+ (id)getObjectWithoutNullsForObject:(id)object
{
    id objectWithoutNulls;

    if ([object isKindOfClass:[NSDictionary class]])
    {
        NSMutableDictionary *dictionary = ((NSDictionary *)object).mutableCopy;

        [dictionary removeObjectsForKeys:[dictionary allKeysForObject:[NSNull null]]];

        for (NSString *key in dictionary.allKeys)
        {
            dictionary[key] = [self getObjectWithoutNullsForObject:dictionary[key]];
        }

        objectWithoutNulls = dictionary;
    }
    else if ([object isKindOfClass:[NSArray class]])
    {
        NSMutableArray *array = ((NSArray *)object).mutableCopy;

        [array removeObject:[NSNull null]];

        for (NSUInteger index = 0; index < array.count; index++)
        {
            array[index] = [self getObjectWithoutNullsForObject:array[index]];
        }

        objectWithoutNulls = array;
    }
    else if ([object isKindOfClass:[NSNull class]])
    {
        objectWithoutNulls = Nil;
    }
    else
    {
        objectWithoutNulls = object;
    }

    return objectWithoutNulls;
}


文章来源: Removing nulls from a JSON structure recursively