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] 、数値オブジェクトを置き換えることはできませんよね?だから私は今、データを再帰的に調べて、全体の変更可能なバージョンを形成しています.1つのインスタンスでは機能しましたが、今で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];

これにより、すべてのコンテナが変更可能になりますが、リーフノード(NSStringなど)は不変のままになります。葉を変更可能にするオプションもあります。

于 2010-01-26T02:00:59.097 に答える
8

通常、ロードと保存を処理するカスタム クラスを 1 つ以上作成する方が簡単だと思います。これにより、配列を明示的に 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これが完了すると、すべてのパッケージ化コードとアンパッケージ化コードをandsaveToFileメソッドにカプセル化できます。このアプローチの主な利点は、メイン プログラムが非常に単純になり、データ構造の要素にプロパティとしてアクセスできるようになることです。

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

必要なのは、深く変更可能なコピーです。ココアにはそれを行う方法が含まれていません。数人の人々が以前にそのようなディープコピーの実装を書いたことがあります()。

ただし、 CoreFoundationにはCFPropertyListAPIが含まれています。これは、プロパティリストオブジェクトの深い可変コピーの作成と、可変データ型としてディスクからのプロパティリストの読み取りの両方をサポートしています。(もちろん、Core FoundationのプロパティリストタイプはCocoaのプロパティリストタイプと無料でブリッジされます。つまり、それらの間で変換する必要はありません。NSArrayはCFArrayであり、その逆も同様です。)

于 2010-01-26T01:38:31.040 に答える