存储和检索多维NSMutableArrays的最佳方法是什么?

时间:2010-01-26 00:56:21

标签: iphone objective-c nsmutablearray plist nsmutabledictionary

我将一堆数据存储在.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什么时候整个事情是可变的。

有更简单/更好的方法吗?如果它有所不同,我的数据只是整数和布尔值。

3 个答案:

答案 0 :(得分:9)

您应该使用NSPropertyListSerialization而不是编写所有自定义类垃圾。具体来说,请参阅propertyListWithData:options:format:error:方法。用法示例:

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

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

答案 1 :(得分:8)

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

  

<强> MyThing.h

@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
  

<强> MyThing.m

@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];

答案 2 :(得分:1)

你想要的是一个深刻的可变副本。可可不包括这样做的方法。一些人在(example)之前编写了这样的深层复制实现。

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