5

我存儲在一個文件中的.plist一組數據(在申請文件的文件夾),它的結構是這樣的:什麼是最好的方式來存儲和檢索多維NSMutableArrays?

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

有沒有更容易/更好的方法來做到這一點?如果它有所作爲,我的數據只是整數和布爾值。

+0

你能給我們提供更多的信息,比如什麼對象正在發送這個方法,並且可能發佈你用來形成新版本的代碼,以及運行時錯誤是由哪些代碼生成的? – 2010-01-26 01:10:31

+0

在開始編輯數值之前,您還正在製作數組的可變副本嗎? – vfn 2010-01-26 01:11:30

回答

9

而不是寫所有定製類垃圾,你應該使用NSPropertyListSerialization。具體來說,請參閱propertyListWithData:options:format:error:方法。實例:

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

這將使所有的容器可變的,但保持葉節點(例如NSString的)不變。還有一個選項可以讓葉子變化。

+0

+1這很吸引人。Apple的文檔指出,在閱讀時不會使用'options'參數(如您在這裏展示的那樣),但實際上可以在*寫* plist文件時使用,以便讀取時的數據是可變的。請參閱http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSPropertyListSerialization_Class/Reference/Reference.html – 2010-01-26 02:22:35

+0

我仍然會爭取一個自定義類,以獲得面向對象的OO好處訪問器以及封裝讀寫方法,但這種技術對於那些簡單的讀取 - 修改 - 寫入有效的場合肯定有幫助。好東西! – 2010-01-26 02:27:11

+0

是的,我爲了方便去了自定義類路線,但是這看起來相當簡單。感謝您的意見。 – kbanman 2010-01-26 03:16:28

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]; 
+0

哇,這是相當徹底的答案,先生:) 這很有道理,我不知道爲什麼它沒有跨過我的腦海。 非常感謝! – kbanman 2010-01-26 01:38:03

1

你想要的是一個深刻的可變副本。可可不包括一種方法來做到這一點。有幾個人在(example)之前編寫了這樣的深度拷貝實現。

但是,Core Foundation包含CFPropertyList API,它既支持創建屬性列表對象的深度可變副本,也支持從磁盤讀取屬性列表中的可變數據類型。 (當然,Core Foundation的屬性列表類型與Cocoa's免費橋接,這意味着您不必在它們之間進行轉換 - NSArray是CFArray,反之亦然。)

相關問題