将对象添加到从 NSUserDefaults 加载的 NSMutableDictionary 中的数组

Add object to array within NSMutableDictionary loaded from NSUserDefaults

我在 NSMutableDictionary 中有一个数组,我想向它添加对象。使用我当前的方法,我收到一条错误消息,指出该数组是不可变的。

我认为问题出在我将字典保存到 NSUserDefaults 时。我正在检索它是 NSDictionary 但同时我正在创建一个包含内容的新 NSMutableDictionary

但是,数组似乎是不可变的。如何替换字典中的数组?

我的字典是这样的:

NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:[NSNumber numberWithInt:0], nil];

NSDictionary *dict = @{

                     @"firstKey": @{
                                     @"theArray":array,
                                   }

                      };

NSMutableDictionary *mutDict = [[NSMutableDictionary alloc] initWithDictionary:dict];

我正在尝试添加这样的对象:

[[[mutDict objectForKey:@"firstKey"] objectForKey:@"theArray"] addObject:[NSNumber numberWithInt:5]];

在保存到 NSUserDefaults

之前,我可以将对象添加到 mutDict 中的数组

从 NSUserDefaults 加载后尝试将其添加到字典中的数组时收到的错误消息:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'

您可以直接将对象添加到数组中:

NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:[NSNumber numberWithInt:0], nil];

NSDictionary *dict = @{

                     @"firstKey": @{
                                     @"theArray":array,
                                   }

                      };

NSMutableDictionary *mutDict = [[NSMutableDictionary alloc] initWithDictionary:dict];

//Since Objective-C objects are always passed by reference (using pointers) you can add object to the array
[array addObject:[NSNumber numberWithInt:55]];

Swift 将对象添加到作为字典一部分的数组的示例。

let arr = [0] // note that initial array may be immutable

var dict = ["fK": ["a":arr]] // even if "arr" will be mutable, but "dict" immutable

dict["fK"]!["a"]!.append(3) // this will not work. "dict" must be mutable

println(dict) //[fK: [a: [0, 3]]]

另一种方法

var arr = [0] // initial array must be mutable

var dict = ["fK": ["a":arr]] // in both cases dictionary must be mutable 

arr.append(3)

let newArr = arr

dict["fK"]!["a"]! = newArr // because we change it's content

println(dict) //[fK: [a: [0, 3]]]

以下是 the documentation for dictionaryForKey: 在 NSUserDefaults 上的说法:

Special Considerations

The returned dictionary and its contents are immutable, even if the values you >originally set were mutable.

因此,当您从 NSUserDefaults 检索字典时,字典本身和其中的所有集合都是不可变的。您可以使顶级字典可变(我假设您正在这样做),但这不会向下传播到现在不可变的 NSArrays,它们是字典中的值。

解决此问题的唯一方法是检查返回的字典并将不可变的 NSArray 替换为可变的对应项。它可能看起来像这样。

- (NSMutableDictionary *)deepMutableCopyOfDictionary:(NSDictionary *)dictionary
{
    NSMutableDictionary *mutableDictionary = [dictionary mutableCopy];
    for (id key in [mutableDictionary allKeys]) {
        id value = mutableDictionary[key];
        if ([value isKindOfClass:[NSDictionary class]]) {
            // If the value is a dictionary make it mutable and call recursively
            mutableDictionary[key] = [self deepMutableCopyOfDictionary:dictionary[key]];
        }
        else if ([value isKindOfClass:[NSArray class]]) {
            // If the value is an array, make it mutable
            mutableDictionary[key] = [(NSArray *)value mutableCopy];
        }
    }
    return mutableDictionary;
}

老实说,尽管听起来您使用 NSUserDefaults 的目的比它的预期要复杂得多。如果你想持久化复杂的数据结构,那么你应该研究像 Core Data 这样的东西,或者如果这看起来有点矫枉过正,请看看 NSKeyedArchiver.