5

我将一堆数据存储在一个 .plist 文件中(在应用程序文档文件夹中),它的结构如下:

Dictionary {
    "description" = "String Value",
    "sections" = Array (
        Array (
            Number,
            ...
            Number
        ),
        Array (
            Number,
            ...
            Number
        )
    ),
    "items" = Array (
        Array (
            Number,
            ...
            Number
        ),
        Array (
            Number,
            ...
            Number
        )
    )
}

如果我只是检索它,
NSMutableDictionary *d = [[NSMutableDictionary alloc] initWithContentsOfFile:plistFile] 我将无法替换数字对象,对吗?所以我现在正在遍历数据并形成整个事物的可变版本,它在一个实例中起作用,但现在它告诉我mutating method sent to immutable object整个事物何时是可变的。

有没有更简单/更好的方法来做到这一点?如果它有所作为,我的数据只是整数和布尔值。

4

3 回答 3

9

您应该使用NSPropertyListSerialization. 具体看propertyListWithData:options:format:error:方法。示例用法:

NSMutableDictionary *d = [NSPropertyListSerialization propertyListWithData:[NSData dataWithContentsOfFile:@"path/to/file"] 
                                                                   options:NSPropertyListMutableContainers
                                                                    format:NULL
                                                                     error:NULL];

这将使所有容器可变,但保持叶节点(例如 NSStrings)不可变。还有一个选项可以使叶子也可变。

于 2010-01-26T02:00:59.097 回答
8

我通常发现创建一个或多个自定义类来处理加载和保存更容易。这使您可以将数组显式转换为 mutableArrays:

我的东西

@interface MyThing : NSObject
{
    NSString * description;
    NSMutableArray * sections;
    NSMutableArray * items;
}
@property (copy) NSString * description;
@property (readonly) NSMutableArray * sections;
@property (readonly) NSMutableArray * items;
- (void)loadFromFile:(NSString *)path;
- (void)saveToFile:(NSString *)path;
@end

我的东西

@implementation MyThing
@synthesize description;
@synthesize sections
@synthesize items;

- (id)init {
    if ((self = [super init]) == nil) { return nil; }
    sections = [[NSMutableArray alloc] initWithCapacity:0];
    items = [[NSMutableArray alloc] initWithCapacity:0];
    return self;
}

- (void)dealloc {
    [items release];
    [sections release];
}

- (void)loadFromFile:(NSString *)path {
    NSDictionary * dict = [NSDictionary dictionaryWithContentsOfFile:path];
    [self setDescription:[dict objectForKey:@"description"]];
    [sections removeAllObjects];
    [sections addObjectsFromArray:[dict objectForKey:@"sections"]];
    [items removeAllObjects];
    [items addObjectsFromArray:[dict objectForKey:@"items"]]; 
}

- (void)saveToFile:(NSString *)path {
    NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:
                           description, @"description",
                           sections, @"sections",
                           items, @"items",
                           nil];
    [dict writeToFile:path atomically:YES];
}

@end;

完成后,您可以将所有打包和解包代码封装在loadFromFilesaveToFile方法中。这种方法的主要好处是您的主程序变得更加简单,并且它允许您将数据结构的元素作为属性访问:

MyThing * thing = [[MyThing alloc] init];
[thing loadFromFile:@"..."];
...
thing.description = @"new description";
[thing.sections addObject:someObject];
[thing.items removeObjectAtIndex:4];
...
[thing saveToFile:@"..."];
[thing release];
于 2010-01-26T01:26:52.627 回答
1

你想要的是一个深层的可变副本。可可不包括一种方法来做到这一点。之前有几个人写过这样的深拷贝实现(例子)。

但是,Core Foundation 包含CFPropertyList API,它确实支持创建属性列表对象的深层可变副本以及从磁盘读取属性列表作为可变数据类型。(当然,Core Foundation 的属性列表类型是与 Cocoa 的免费桥接的,这意味着您不必在它们之间进行转换——NSArray 是 CFArray,反之亦然。)

于 2010-01-26T01:38:31.040 回答