[iPhone Dev] NSDictionary, NSArray 등의 저장에 대해

No Comments

NSUserDefaults를 이용해서 NSString 기반으로 앱의 데이터를 저장하는 것은 손쉽지만, NSDictionary나 NSArry 등의 데이터를 저장하기는 불편할 것입니다.

NSPropertyListSerialization을 이용하는 방법을 주로 사용했었는데요, NSDictionary의 writeToFile:automatically과 dictionaryWithContentsOfFile: 을 이용해서 좀 더 직관적으로 하는 것도 좋을 것 같아서 포스팅 해봅니다.

 

[1] NSDictionary의 writeToFile:automatically과 dictionaryWithContentsOfFile: 이용

저장할 때는 writeToFile:automatically을 불러올 때는 dictionaryWithContentsOfFile: 을 이용하면 될 것입니다.

그리고 NSString의 stringByExpandingTildeInPath을 이용해서 Documents의 path도 쫌 더직관적으로 얻어 오면 다음과 같은 코드가 만들어질 것입니다.
[저장하기]

-(void)saveDic:(NSMutableDictionary*)aDic ForKey:(NSString*)aKey {
if( aDic == nil || aKey == nil ) {
return;
}

NSString* dataPath = [[NSString stringWithFormat:@"~/Documents/%@", aKey] stringByExpandingTildeInPath];

[aDic writeToFile:dataPath atomically:YES];

}

 

[불러오기]

-(NSMutableDictionary*)loadDicForKey:(NSString*)aKey {
if( aKey == nil ) {
return nil;
}

NSString* dataPath = [[NSString stringWithFormat:@"~/Documents/%@", aKey] stringByExpandingTildeInPath];

return [NSMutableDictionary dictionaryWithContentsOfFile:dataPath];
}

 

[사용 예]

NSPropertyListSerialization 의 사용에도 마찬가지지만, (실수에 의한) memory leak을 막기 위해서 데이터를 가지고 있는 object는 property로 처리하는 것이 좋은 것 같습니다.

// dictionaryWithContentsOfFile 이용
NSString* testKey = @"testKey";

self.dataDic = [self loadDicForKey:testKey];

if( self.dataDic ) {
NSLog(@"testKey (first): %@", self.dataDic);
}

[self.dataDic setObject:[NSArray arrayWithObjects:@"a", @"b", @"c", nil] forKey:@"abc"];

[self saveDic:self.dataDic ForKey:testKey];
self.dataDic = nil;

self.dataDic = [self loadDicForKey:testKey];

if( self.dataDic ) {
NSLog(@"testKey (second): %@", self.dataDic);
}

[2] NSPropertyListSerialization 이용

아래 코드에 주석으로 표기 했지만, propertyListFromData:mutabilityOption:format:error: 이나 dataFromPropertyList:format:error: 등은 곧 decprecate될 것이라고 하니 대체되는 method를 사용해야할 것입니다.

그리고 , [1]에서도 이야기 했지만, 데이터를 받는 객체는 property로 처리해줘야 memory leak을 깔끔하게 없앨 수 있겠죠.

 

[저장 및 불러오기]

 

-(NSMutableDictionary*)restoreDataForKey:(NSString*)aKey {

if( aKey == nil ) {
return nil;
}

NSString *finalPath = nil;

NSData *plistData;
NSError *error;
NSPropertyListFormat format;

// normal
finalPath = [self getFilePathForkey:aKey];
plistData = [NSData dataWithContentsOfFile:finalPath];

NSMutableDictionary* tempDic = nil;
if( plistData ) {
/*
// propertyListFromData will be deprecated soon.
dataDic = [NSPropertyListSerialization propertyListFromData:plistData
mutabilityOption:NSPropertyListMutableContainers
format:&format
errorDescription:&error];
*/
tempDic = [NSPropertyListSerialization propertyListWithData:plistData options:NSPropertyListMutableContainers format:&format error:&error];

}

if(tempDic == nil) {
tempDic = [[[NSMutableDictionary alloc] init] autorelease];
}

return tempDic;
}

-(void)storeData:(NSMutableDictionary*)aDic ForKey:(NSString*)aKey {

if( aDic == nil || aKey == nil ) {
return;
}

NSString *finalPath = nil;
NSData *xmlData;
NSError *error;

// normal
if(aDic != nil ) {

finalPath = [self getFilePathForkey:aKey];

/*
dataFromPropertyList will be deprecated soon.
xmlData = [NSPropertyListSerialization dataFromPropertyList:aDic
format:NSPropertyListXMLFormat_v1_0
errorDescription:&error];
*/

xmlData = [NSPropertyListSerialization dataWithPropertyList:aDic format:NSPropertyListXMLFormat_v1_0 options:0 error:&error];

if(xmlData) {
//NSLog(@"No error creating XML data.");
[xmlData writeToFile:finalPath atomically:YES];
}
else {
NSLog(@"%@", error);
[error release];
}
}
}

 

[사용 예]

// NSPropertyListSerialization 이용
testKey = @"testKey2";
self.dataDic2 = [self restoreDataForKey:testKey];
if( self.dataDic2 ) {
NSLog(@"testKey2 (first): %@", self.dataDic2);
}

[self.dataDic2 setObject:[NSArray arrayWithObjects:@"aa", @"bb", @"cc", nil] forKey:@"aabbcc"];

[self storeData:self.dataDic2 ForKey:testKey];

self.dataDic2 = nil;

self.dataDic2 = [self restoreDataForKey:testKey];

if( self.dataDic2 ) {
NSLog(@"testKey2 (scond): %@", self.dataDic2);
}