【问题标题】:Replace all NSNull objects in an NSDictionary替换 NSDictionary 中的所有 NSNull 对象
【发布时间】:2011-12-25 21:14:18
【问题描述】:

我很好奇,由于 json-framework 的帮助,我目前有一个 NSDictionary,其中一些值设置为 NSNull 对象。

目的是去除所有NSNull 值并将其替换为空字符串。

我确定有人在某处做过这个?毫无疑问,它可能是一个四班轮而且很简单,我只是太累了,无法自己解决这个问题。

【问题讨论】:

标签: objective-c nsstring nsdictionary json-framework nsnull


【解决方案1】:

我已经测试了 Stakenborg 解决方案。它工作得很好,但它有以下问题。例如,如果某个对象预期为数字,则将其转换为 NSNull 可能会导致错误。 我创建了一个新方法来直接删除 NSNull 条目。这样你只需要检查对应的键是否存在。

添加NSDictionary+NullReplacement

- (NSDictionary *)dictionaryByRemovingNulls{
    const NSMutableDictionary *replaced = [self mutableCopy];
    const id nul = [NSNull null];
    
    for (NSString *key in self) {
        id object = [self objectForKey:key];
        if (object == nul) [replaced removeObjectForKey:key];
        
        else if ([object isKindOfClass:[NSDictionary class]]) [replaced setObject:[object dictionaryByRemovingNulls] forKey:key];
        else if ([object isKindOfClass:[NSArray class]]) [replaced setObject:[object arrayByRemovingNulls] forKey:key];
    }
    return [NSDictionary dictionaryWithDictionary:[replaced copy]];
}

NSArray+NullReplacement

- (NSArray *)arrayByRemovingNulls {
    NSMutableArray *replaced = [self mutableCopy];
    const id nul = [NSNull null];

    for (int idx = [replaced count]-1; idx >=0; idx--) {
        id object = [replaced objectAtIndex:idx];
        if (object == nul) [replaced removeObjectAtIndex:idx];
        else if ([object isKindOfClass:[NSDictionary class]]) [replaced replaceObjectAtIndex:idx withObject:[object dictionaryByRemovingNulls]];
        else if ([object isKindOfClass:[NSArray class]]) [replaced replaceObjectAtIndex:idx withObject:[object arrayByRemovingNulls]];
    }
    return [replaced copy];
}

【讨论】:

    【解决方案2】:

    我对 Jacob 的原始答案进行了一些更改,以将其扩展为处理存储在原始字典中的字典和数组。

    #import "NSDictionary+NullReplacement.h"
    #import "NSArray+NullReplacement.h"
    
    @implementation NSDictionary (NullReplacement)
    
    - (NSDictionary *)dictionaryByReplacingNullsWithBlanks {
        const NSMutableDictionary *replaced = [self mutableCopy];
        const id nul = [NSNull null];
        const NSString *blank = @"";
        
        for (NSString *key in self) {
            id object = [self objectForKey:key];
            if (object == nul) [replaced setObject:blank forKey:key];
            else if ([object isKindOfClass:[NSDictionary class]]) [replaced setObject:[object dictionaryByReplacingNullsWithBlanks] forKey:key];
            else if ([object isKindOfClass:[NSArray class]]) [replaced setObject:[object arrayByReplacingNullsWithBlanks] forKey:key];
        }
        return [NSDictionary dictionaryWithDictionary:[replaced copy]];
    }
    
    @end
    

    当然还有一个数组类:

    #import "NSArray+NullReplacement.h"
    #import "NSDictionary+NullReplacement.h"
    
    @implementation NSArray (NullReplacement)
    
    - (NSArray *)arrayByReplacingNullsWithBlanks  {
        NSMutableArray *replaced = [self mutableCopy];
        const id nul = [NSNull null];
        const NSString *blank = @"";
        for (int idx = 0; idx < [replaced count]; idx++) {
            id object = [replaced objectAtIndex:idx];
            if (object == nul) [replaced replaceObjectAtIndex:idx withObject:blank];
            else if ([object isKindOfClass:[NSDictionary class]]) [replaced replaceObjectAtIndex:idx withObject:[object dictionaryByReplacingNullsWithBlanks]];
            else if ([object isKindOfClass:[NSArray class]]) [replaced replaceObjectAtIndex:idx withObject:[object arrayByReplacingNullsWithBlanks]];
        }
        return [replaced copy];
    }
    
    @end
    

    有了这个,你可以获取任何数组或字典并递归地清除所有 [NSNull null] 实例。

    附:为了完整起见,这里是头文件:

    @interface NSDictionary (NullReplacement)
    
    - (NSDictionary *)dictionaryByReplacingNullsWithBlanks;
    
    @end
    

    还有数组头:

    @interface NSArray (NullReplacement)
    
    - (NSArray *)arrayByReplacingNullsWithBlanks;
    
    @end
    

    【讨论】:

    【解决方案3】:

    这是我的解决方案:

    + (NSDictionary *)cleanNullInJsonDic:(NSDictionary *)dic
    {
        if (!dic || (id)dic == [NSNull null])
        {
            return dic;
        }
        NSMutableDictionary *mulDic = [[NSMutableDictionary alloc] init];
        for (NSString *key in [dic allKeys])
        {
            NSObject *obj = dic[key];
            if (!obj || obj == [NSNull null])
            {
    //            [mulDic setObject:[@"" JSONValue] forKey:key];
            }else if ([obj isKindOfClass:[NSDictionary class]])
            {
                [mulDic setObject:[self cleanNullInJsonDic:(NSDictionary *)obj] forKey:key];
            }else if ([obj isKindOfClass:[NSArray class]])
            {
                NSArray *array = [BasicObject cleanNullInJsonArray:(NSArray *)obj];
                [mulDic setObject:array forKey:key];
            }else
            {
                [mulDic setObject:obj forKey:key];
            }
        }
        return mulDic;
    }
    
    
    + (NSArray *)cleanNullInJsonArray:(NSArray *)array
    {
        if (!array || (id)array == [NSNull null])
        {
            return array;
        }
        NSMutableArray *mulArray = [[NSMutableArray alloc] init];
        for (NSObject *obj in array)
        {
            if (!obj || obj == [NSNull null])
            {
    //            [mulArray addObject:[@"" JSONValue]];
            }else if ([obj isKindOfClass:[NSDictionary class]])
            {
                NSDictionary *dic = [self cleanNullInJsonDic:(NSDictionary *)obj];
                [mulArray addObject:dic];
            }else if ([obj isKindOfClass:[NSArray class]])
            {
                NSArray *a = [BasicObject cleanNullInJsonArray:(NSArray *)obj];
                [mulArray addObject:a];
            }else
            {
                [mulArray addObject:obj];
            }
        }
        return mulArray;
    }    
    

    【讨论】:

    • 在我的字典包含字典和数组对象的情况下,这就像一个魅力。谢谢你:)
    【解决方案4】:

    nsnull 上返回 nil 的类别似乎也有意义,至少对我而言。那里有几个。一个使所有调用都返回 nil,这似乎是有道理的。抱歉没有链接。我猜如果您以后需要使用 nspropertylistserialization,该类别可能不适合您。

    【讨论】:

      【解决方案5】:
      -(NSDictionary*)stripNulls:(NSDictionary*)dict{
      
          NSMutableDictionary *returnDict = [NSMutableDictionary new];
          NSArray *allKeys = [dict allKeys];
          NSArray *allValues = [dict allValues];
      
          for (int i=0; i<[allValues count]; i++) {
              if([allValues objectAtIndex:i] == (NSString*)[NSNull null]){
                  [returnDict setValue:@"" forKey:[allKeys objectAtIndex:i]];
              }
          else
              [returnDict setValue:[allValues objectAtIndex:i] forKey:[allKeys objectAtIndex:i]];
          }
      
      return returnDict;
      }
      

      【讨论】:

        【解决方案6】:

        真的很简单:

        @interface NSDictionary (JRAdditions)
        - (NSDictionary *)dictionaryByReplacingNullsWithStrings;
        @end
        
        @implementation NSDictionary (JRAdditions)
        
        - (NSDictionary *)dictionaryByReplacingNullsWithStrings {
           const NSMutableDictionary *replaced = [self mutableCopy];
           const id nul = [NSNull null];
           const NSString *blank = @"";
        
           for(NSString *key in self) {
              const id object = [self objectForKey:key];
              if(object == nul) {
                 //pointer comparison is way faster than -isKindOfClass:
                 //since [NSNull null] is a singleton, they'll all point to the same
                 //location in memory.
                 [replaced setObject:blank 
                              forKey:key];
              }
           }
        
           return [replaced copy];
        }
        
        @end
        

        用法:

        NSDictionary *someDictThatHasNulls = ...;
        NSDictionary *replacedDict = [someDictThatHasNulls dictionaryByReplacingNullsWithStrings];
        

        【讨论】:

        • 或者,由于NSNull是单例,你可以直接测试值指针:if([self objectForKey:key]==[NSNull null])
        • Yes.. 但是如果字典包含 NSArray 的 NULL 怎么办?还是其他具有 NULL 值的 NSDictionary?小心使用它!我强烈推荐使用 Stakenborg 对该方法的修改,如下所述!
        • 使用下面 Stakenborg 的方法!
        • 复制粘贴到哪里?当我尝试它并粘贴到下面我想要的文件时,这给了我错误,对不起,我是 iOS 新手
        【解决方案7】:

        翻阅字典寻找 NSNull 是解决问题的一种方法,但我采取了一种稍微懒惰的方法。你可以指定一个空字符串,而不是 nil,但原理是一样的。

        CPJSONDictionary.h

        @interface NSDictionary (CPJSONDictionary)
        - (id)jsonObjectForKey:(id)aKey;
        @end
        

        CPJSONDictionary.m

        @implementation NSDictionary (CPJSONDictionary)
        
        - (id)jsonObjectForKey:(id)aKey {
            id object = [self objectForKey:aKey];
            if ([object isKindOfClass:[NSNull class]]) {
                object = nil;
            }
        
            return object;
        }
        
        @end
        

        【讨论】:

          【解决方案8】:

          另一种变化:

          NSDictionary * NewDictionaryReplacingNSNullWithEmptyNSString(NSDictionary * dict) {
              NSMutableDictionary * const m = [dict mutableCopy];    
              NSString * const empty = @"";
              id const nul = [NSNull null];
              NSArray * const keys = [m allKeys];
              for (NSUInteger idx = 0, count = [keys count]; idx < count; ++idx) {
                  id const key = [keys objectAtIndex:idx];
                  id const obj = [m objectForKey:key];
                  if (nul == obj) {
                      [m setObject:empty forKey:key]; 
                  }
              }
          
              NSDictionary * result = [m copy];
              [m release];
              return result;
          }
          

          结果与 Jacob 的结果相同,看起来几乎相同,但在我进行的测试中,速度和内存要求是二分之一到三分之一(ARC 或 MRC)。当然,你也可以将它作为一个分类方法使用。

          【讨论】:

          • 简单代码,但它只是替换了 NSDictionary 根分支中的空值,因此无法从 JSON 服务中从我的 NSDictionary 值中删除空值。下面 Stakenborg 的代码很有效。
          猜你喜欢
          • 1970-01-01
          • 2014-09-25
          • 2018-02-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-03
          相关资源
          最近更新 更多