【问题标题】:Replace occurrences of NSNull in nested NSDictionary替换嵌套 NSDictionary 中出现的 NSNull
【发布时间】:2012-08-31 10:49:07
【问题描述】:

这个问题类似于this question,但是这个方法只适用于字典的根级别。

我希望用空字符串替换任何出现的NSNull 值,以便我可以将完整的字典保存到 plist 文件中(如果我将它与 NSNull 一起添加,文件将不会写入)。

然而,我的字典里面有嵌套的字典。像这样:

"dictKeyName" = {
    innerStrKeyName = "This is a string in a dictionary";
    innerNullKeyName = "<null>";
    innerDictKeyName = {
        "innerDictStrKeyName" = "This is a string in a Dictionary in another Dictionary";
        "innerDictNullKeyName" = "<null>";
    };
};

如果我使用:

@interface NSDictionary (JRAdditions)
- (NSDictionary *) dictionaryByReplacingNullsWithStrings;
@end

@implementation NSDictionary (JRAdditions)

- (NSDictionary *) dictionaryByReplacingNullsWithStrings {

    const NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary:self];
    const id nul = [NSNull null];
    const NSString *blank = @"";

    for(NSString *key in replaced) {
        const id object = [self objectForKey:key];
        if(object == nul) {
            [replaced setObject:blank forKey:key];
        }
    }
    return [NSDictionary dictionaryWithDictionary:replaced];
}

@end

我得到这样的东西:

"dictKeyName" = {
    innerStrKeyName = "This is a string in a dictionary";
    innerNullKeyName = ""; <-- this value has changed
    innerDictKeyName = {
        "innerDictStrKeyName" = "This is a string in a Dictionary in another Dictionary";
        "innerDictNullKeyName" = "<null>"; <-- this value hasn't changed
    };
};

有没有办法从包括嵌套字典在内的所有字典中找到每个 NSNull 值...?

编辑: 数据是从 JSON 提要中提取的,因此我收到的数据是动态的(我不想在每次提要更改时都更新应用程序)。

【问题讨论】:

  • 另外你真的应该发布实际代码 ""
  • 这是我得到的实际响应。我正在解析 JSON 提要,字典是响应。当我将其注销时,它显示为“”,并在查找和替换 for 循环中被识别为 [NSNull null]。
  • 您拥有的代码是用来操作 NSDictionary 的,因此当您解析 JSON 时调用该方法来删除 NSNulls
  • 您有任何示例说明如何执行此操作吗?
  • 您还有这个问题吗?是否有任何答案解决了问题?

标签: ios plist nsdictionary replace nsnull


【解决方案1】:

对该方法稍加修改即可使其递归:

@interface NSDictionary (JRAdditions)
- (NSDictionary *) dictionaryByReplacingNullsWithStrings;
@end

@implementation NSDictionary (JRAdditions)

- (NSDictionary *) dictionaryByReplacingNullsWithStrings {
    const NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary: self];
    const id nul = [NSNull null];
    const NSString *blank = @"";

    for (NSString *key in self) {
        const id object = [self objectForKey: key];
        if (object == nul) {
            [replaced setObject: blank forKey: key];
        }
        else if ([object isKindOfClass: [NSDictionary class]]) {
            [replaced setObject: [(NSDictionary *) object dictionaryByReplacingNullsWithStrings] forKey: key];
        }
    }
    return [NSDictionary dictionaryWithDictionary: replaced];
}

请注意,快速枚举现在位于 self 而不是 replaced

使用上面的代码,这个例子:

NSMutableDictionary *dic1 = [NSMutableDictionary dictionary];
[dic1 setObject: @"string 1" forKey: @"key1.1"];
[dic1 setObject: [NSNull null] forKey: @"key1.2"];

NSMutableDictionary *dic2 = [NSMutableDictionary dictionary];
[dic2 setObject: @"string 2" forKey: @"key2.1"];
[dic2 setObject: [NSNull null] forKey: @"key2.2"];

[dic1 setObject: dic2 forKey: @"key1.3"];

NSLog(@"%@", dic1);
NSLog(@"%@", [dic1 dictionaryByReplacingNullsWithStrings]);

呈现这个结果:

2012-09-01 08:30:16.210 Test[57731:c07] {
    "key1.1" = "string 1";
    "key1.2" = "<null>";
    "key1.3" =     {
        "key2.1" = "string 2";
        "key2.2" = "<null>";
    };
}
2012-09-01 08:30:16.212 Test[57731:c07] {
    "key1.1" = "string 1";
    "key1.2" = "";
    "key1.3" =     {
        "key2.1" = "string 2";
        "key2.2" = "";
    };

【讨论】:

  • 真的吗?我在其输出中添加了一个使用示例。
  • 最后一行是多余的;改为return replaced; 就足够了。
  • 如果对象是NSArray怎么办?
  • 如何处理嵌套的 json 字符串,见这篇文章stackoverflow.com/questions/48009583/…
  • 即使当前实现有效,我也会使用 for (NSString *key in [self allKeys]) - 因为它的可读性较差,而且您需要深入挖掘才能知道快速枚举over NSDictionary 枚举键。 (可以是值,或对,或其他任何东西。
【解决方案2】:

它对我有用,我使用嵌套循环将包括 NSArray 在内的整个字典中的所有 NULL 替换为 nil。

- (NSDictionary *) dictionaryByReplacingNullsWithNil:(NSDictionary*)sourceDictionary {

    NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary:sourceDictionary];
    const id nul = [NSNull null];

    for(NSString *key in replaced) {
        const id object = [sourceDictionary objectForKey:key];
        if(object == nul) {
            [replaced setValue:nil forKey:key];
        }
    }
    return [NSDictionary dictionaryWithDictionary:replaced];
}

-(NSDictionary *) nestedDictionaryByReplacingNullsWithNil:(NSDictionary*)sourceDictionary
{
    NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary:sourceDictionary];
    const id nul = [NSNull null];
    const NSString *blank = @"";
    [sourceDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
        object = [sourceDictionary objectForKey:key];
        if([object isKindOfClass:[NSDictionary class]])
        {
            NSDictionary *innerDict = object;
            [replaced setObject:[self nestedDictionaryByReplacingNullsWithNil:innerDict] forKey:key];

        }
        else if([object isKindOfClass:[NSArray class]]){
            NSMutableArray *nullFreeRecords = [NSMutableArray array];
            for (id record in object) {

                if([record isKindOfClass:[NSDictionary class]])
                {
                    NSDictionary *nullFreeRecord = [self nestedDictionaryByReplacingNullsWithNil:record];
                    [nullFreeRecords addObject:nullFreeRecord];
                }
            }
            [replaced setObject:nullFreeRecords forKey:key];
        }
        else
        {
            if(object == nul) {
                [replaced setObject:blank forKey:key];
            }
        }
    }];

    return [NSDictionary dictionaryWithDictionary:replaced];  
}

【讨论】:

  • 这个实现比公认的更有用,因为它考虑了数组
  • 此实现不会考虑包含非字典数据(例如字符串或数组)的数组。它将返回一个空数组
  • 对不起...但是 [someMutableDictionary setValue:nil forKey @"someKey"] 不会在字典中引入 nil - 这会立即崩溃。相反,它完全删除了键/值对。我不确定这是否能很好地满足 OP 的需求
【解决方案3】:

如果有人在 swift 1.2 中需要这个,这里是 sn-p:

class func removeNullsFromDictionary(origin:[String:AnyObject]) -> [String:AnyObject] {
    var destination:[String:AnyObject] = [:]
    for key in origin.keys {
        if origin[key] != nil && !(origin[key] is NSNull){
            if origin[key] is [String:AnyObject] {
                destination[key] = self.removeNullsFromDictionary(origin[key] as! [String:AnyObject])
            } else if origin[key] is [AnyObject] {
                let orgArray = origin[key] as! [AnyObject]
                var destArray: [AnyObject] = []
                for item in orgArray {
                    if item is [String:AnyObject] {
                        destArray.append(self.removeNullsFromDictionary(item as! [String:AnyObject]))
                    } else {
                        destArray.append(item)
                    }
                }
                destination[key] = destArray
            } else {
                destination[key] = origin[key]
            }
        } else {
            destination[key] = ""
        }
    }
    return destination
}

【讨论】:

  • 有效,但您忘记了循环结束时的 destination[key] = destArray
  • @Danilo,感谢您的评论,我编辑了 sn-p
【解决方案4】:

以下方法适用于任意数量的嵌套字典数组:

- (NSMutableDictionary *)dictionaryByReplacingNullsWithStrings:(NSDictionary *)jobList
{
    NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary:jobList];
    const id nul = [NSNull null];
    const NSString *blank = @"";

    for (NSString *key in [replaced allKeys])
    {
        id object = [replaced objectForKey:key];
        if (object == nul)
        {
            [replaced setObject:blank
                         forKey:key];
        }
        else
        if ([object isKindOfClass:[NSDictionary class]])
        {
            [replaced setObject:[self replaceNullInNested:object]
                         forKey:key];
        }
        else
        if ([object isKindOfClass:[NSArray class]])
        {
            NSMutableArray *dc = [[NSMutableArray alloc] init];
            for (NSDictionary *tempDict in object)
            {
                [dc addObject:[self dictionaryByReplacingNullsWithStrings:tempDict]];
            }
            [replaced setObject:dc
                         forKey:key];
        }
    }
    return replaced;
}

- (NSMutableDictionary *)replaceNullInNested:(NSDictionary *)targetDict
{
    // make it to be NSMutableDictionary in case that it is nsdictionary
    NSMutableDictionary *m = [targetDict mutableCopy];
    NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary:m];
    const id nul = [NSNull null];
    const NSString *blank = @"";

    for (NSString *key in [replaced allKeys])
    {
        const id object = [replaced objectForKey:key];
        if (object == nul)
        {
            [replaced setObject:blank
                         forKey:key];
        }
        else
        if ([object isKindOfClass:[NSArray class]])
        {
//            NSLog(@"found null inside and key is %@", key);
            // make it to be able to set value by create a new one
            NSMutableArray *a = [object mutableCopy];
            for (int i = 0; i < [a count]; i++)
            {
                for (NSString *subKey in [[a objectAtIndex:i] allKeys])
                {
                    if ([[object objectAtIndex:i] valueForKey:subKey] == nul)
                    {
                        [[object objectAtIndex:i] setValue:blank
                                                    forKey:subKey];
                    }
                }
            }
            // replace the updated one with old one
            [replaced setObject:a
                         forKey:key];
        }
    }
    return replaced;
}

我根据需要的功能使用了上述修改方法:

//调用方法

NSMutableDictionary *sortedDict = [[NSMutableDictionary alloc] init];

for (NSString *key in jobList){
    NSMutableArray *tempArray = [[NSMutableArray alloc] init];

    for (NSDictionary *tempDict in [jobList objectForKey:key])
    {
        [tempArray addObject:[self dictionaryByReplacingNullsWithStrings:tempDict]];
    }
    [sortedDict setObject:tempArray forKey:key];
}

【讨论】:

    【解决方案5】:

    这段代码

    @interface NSDictionary (JRAdditions)
        - (NSDictionary *) dictionaryByReplacingNullsWithStrings;
    @end
    

    Monkey 补丁 NSDictionary - 这意味着您可以调用 dictionaryByReplace... 不仅在根目录上,而且在任何嵌套字典上都可以。

    从设计的角度来看,我真的不同意这一点,但它确实解决了你的问题。

    【讨论】:

    • 这个我知道,但是我的数据是动态的,所以我不想每次更新字典都重新发布代码。
    • 检查对象是否为字典,并替换为调用方法的结果。
    【解决方案6】:

    试试这个:

    @interface NSDictionary (JRAdditions)
     - (NSDictionary *) dictionaryByReplacingNullsWithStrings;
     -(NSDictionary *) nestedDictionaryByReplacingNullsWithStrings;
    @end
    
    @implementation NSDictionary (JRAdditions)
    
    - (NSDictionary *) dictionaryByReplacingNullsWithStrings {
    
    const NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary:self];
    const id nul = [NSNull null];
    const NSString *blank = @"";
    
    for(NSString *key in replaced) {
        const id object = [self objectForKey:key];
        if(object == nul) {
            [replaced setObject:blank forKey:key];
        }
    }
    return [NSDictionary dictionaryWithDictionary:replaced];
    }
    
    -(NSDictionary *) nestedDictionaryByReplacingNullsWithStrings
    {  
      const NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary:self];
      const id nul = [NSNull null];
      const NSString *blank = @"";
      for(id *item in replaced) {
        const id object = [self objectForKey:key];
        if([object isKindofClass:[NSDictionary class]])
        {
           NSDictionary *innerDict = object;
           [replaced setObject:[innerDict dictionaryByReplacingNullsWithStrings] forKey:key];
    
        }
        else
        {
         if(object == nul) {
            [replaced setObject:blank forKey:key];
         }
        }
     }
     return [NSDictionary dictionaryWithDictionary:replaced];  
    }
    

    【讨论】:

      【解决方案7】:

      此解决方案适用于数组和字典,也适用于嵌套数组和字典等(递归)。

      - (NSDictionary *)writableDictionary:(NSDictionary *)dictionary
      {
          NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary];
      
          for (id key in mutableDictionary.allKeys)
          {
              id value = mutableDictionary[key];
              mutableDictionary[key] = [self writableValue:value];
          }
      
          return mutableDictionary;
      }
      
      - (NSArray *)writableArray:(NSArray *)array
      {
          NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array];
      
          for (int i = 0; i < mutableArray.count; ++i)
          {
              id value = mutableArray[i];
              mutableArray[i] = [self writableValue:value];
          }
      
          return mutableArray;
      }
      
      - (id)writableValue:(id)value
      {
          if ([value isKindOfClass:[NSNull class]])
          {
              value = @"";
          }
          else if ([value isKindOfClass:[NSDictionary class]])
          {
              value = [self writableDictionary:value];
          }
          else if ([value isKindOfClass:[NSArray class]])
          {
              value = [self writableArray:value];
          }
          return value;
      }
      

      【讨论】:

        【解决方案8】:

        如果您的字典中有数组,上述答案不适合这种情况。看看这个

        +(NSMutableDictionary*)getValuesWithOutNull:(NSDictionary          
             *)yourDictionary{
               NSMutableDictionary *replaced = [NSMutableDictionary 
             dictionaryWithDictionary: yourDictionary];
              id nul = [NSNull null];
              NSString *blank = @"";
        
        for (NSString *key in yourDictionary) {
            const id object = [yourDictionary objectForKey: key];
            if (object == nul) {
                [replaced setObject: blank forKey: key];
            }
            else if ([object isKindOfClass: [NSDictionary class]]) {
                [replaced setObject:[self getValuesWithOutNull:object] 
        forKey:key];
            }
            else if([object isKindOfClass: [NSArray class]])
            {
                NSMutableArray *array  = [NSMutableArray 
        arrayWithArray:object];
                for(int i = 0 ;i < array.count;i++)
                {
                    NSDictionary *dict = [array objectAtIndex:i];
                    [array replaceObjectAtIndex:i withObject:[self 
          getValuesWithOutNull:dict]];
                }
                [replaced setObject:array forKey:key];
            }
         }
          return  replaced;
        
        }
        

        【讨论】:

          猜你喜欢
          • 2011-12-25
          • 1970-01-01
          • 2010-09-21
          • 2018-02-08
          • 2012-07-30
          • 2014-04-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多