存储和检索多维 NSMutableArrays 的最佳方法是啥?
Posted
技术标签:
【中文标题】存储和检索多维 NSMutableArrays 的最佳方法是啥?【英文标题】:What's the best way to store and retrieve multi-dimensional NSMutableArrays?存储和检索多维 NSMutableArrays 的最佳方法是什么? 【发布时间】:2010-01-26 00:56:20 【问题描述】:我将一堆数据存储在 .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
当整个事物是可变的时。
有没有更简单/更好的方法来做到这一点?如果有区别,我的数据只是整数和布尔值。
【问题讨论】:
你能给我们更多的信息,比如这个方法正在发送什么对象,并可能发布你用来形成新版本的代码以及运行时错误是由什么产生的吗? 在开始编辑值之前,您是否还制作了数组的可变副本? 【参考方案1】:您应该使用NSPropertyListSerialization
,而不是编写所有自定义类垃圾。具体来说,请参见propertyListWithData:options:format:error:
方法。示例用法:
NSMutableDictionary *d = [NSPropertyListSerialization propertyListWithData:[NSData dataWithContentsOfFile:@"path/to/file"]
options:NSPropertyListMutableContainers
format:NULL
error:NULL];
这将使所有容器可变,但保持叶节点(例如 NSStrings)不可变。还有一个选项可以使叶子也可变。
【讨论】:
+1 这很有趣。 Apple 的文档声明options
参数在读取时不使用(如您在此处显示的那样),但实际上可以在 写入 plist 文件时使用它,以便数据,当读,是可变的。见developer.apple.com/mac/library/documentation/Cocoa/Reference/…
我仍然主张使用自定义类来获得属性访问器的 OO 优势并封装读取和写入方法,但是这种技术肯定会在那些简单的读取修改的情况下有所帮助-写是有序的。好东西!
是的,为了方便起见,我选择了自定义类路径,但这看起来相当简单。感谢您的意见。
文档有误,非常令人困惑。忽略它。改为阅读头文件 (NSPropertyList.h),它表示在采用 NSPropertyListWriteOptions 参数的两种方法中,它被忽略并且当前设置为零。叹息。【参考方案2】:
我通常发现创建一个或多个自定义类来处理加载和保存更容易。这使您可以将数组显式转换为 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;
完成后,您可以将所有打包和解包代码封装在您的loadFromFile
和saveToFile
方法中。这种方法的主要好处是您的主程序变得更加简单,并且它允许您将数据结构的元素作为属性访问:
MyThing * thing = [[MyThing alloc] init];
[thing loadFromFile:@"..."];
...
thing.description = @"new description";
[thing.sections addObject:someObject];
[thing.items removeObjectAtIndex:4];
...
[thing saveToFile:@"..."];
[thing release];
【讨论】:
哇,这是非常彻底的答案,先生 :) 这很有道理,我不知道为什么我没有想到它。非常感谢!【参考方案3】:你想要的是一个深层次的可变副本。可可不包括一种方法来做到这一点。之前有几个人写过这样的深拷贝实现(example)。
然而,Core Foundation 包含CFPropertyList API,它确实支持创建属性列表对象的深层可变副本以及从磁盘读取属性列表作为可变数据类型。 (当然,Core Foundation 的属性列表类型与 Cocoa 是免费桥接的,这意味着您不必在它们之间进行转换 - NSArray 是 CFArray,反之亦然。)
【讨论】:
以上是关于存储和检索多维 NSMutableArrays 的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
存储少量 NSMutableArrays(使用 plist)?
使用 NSData 和 NSMutableArrays 保存 OS X 游戏数据