obj-c中有一类对象:NSArray,NSDictionary,NSString,NSNumber,NSDate,NSData以及它们的可变版本(指NSMutableArray,NSMutableDictionary...这一类) ,都可以方便的将自身的数据以某种格式(比如xml格式)序列化后保存成本地文件。
示例代码:NSArrayTest.h
#import <Foundation/Foundation.h> #define FILE_NAME @"/tmp/data.txt" @interface NSArrayTest : NSObject { } -(void) Test; @end
NSArrayTest.m
#import "NSArrayTest.h" @implementation NSArrayTest -(void) Test { NSArray *arr = [NSArray arrayWithObjects:@"one",@"two",@"three",nil];//注:最后一个要以nil结尾 [arr writeToFile:FILE_NAME atomically:YES];//(序列化为xml格式后)保存文件 NSArray *arr2 = [NSArray arrayWithContentsOfFile:FILE_NAME];//read file NSLog(@"%@",arr2); } @end
运行结果:
2011-03-03 14:20:01.501 pList[1246:a0f] (
one,
two,
three
)
one,
two,
three
)
如果查看/tmp/data.txt,能看到下面的内容:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <array> <string>one</string> <string>two</string> <string>three</string> </array> </plist>
如果你用来存放数据的类是自己定义的,并不是上面这些预置的对象,那么就要借助正式协议NSCoding来实现序列化和反序列化。
比如,我们有一个自己的类Sample.h
#import <Foundation/Foundation.h> @interface Sample : NSObject<NSCoding> { NSString* name; int magicNumber; float shoeSize; NSMutableArray *subThingies; } @property(copy) NSString* name; @property int magicNumber; @property float shoeSize; @property (retain) NSMutableArray *subThingies; -(id) initWithName:(NSString *)n magicNumber:(int)m shoeSize:(float) ss; @end
这里我们定义几个不同类型的属性,有字符串,有整数,有浮点数,还有一个可变长的数组对象
Sample.m
#import "Sample.h" @implementation Sample @synthesize name; @synthesize magicNumber; @synthesize shoeSize; @synthesize subThingies; -(id) initWithName:(NSString *)n magicNumber:(int)m shoeSize:(float)ss { if (self=[super init]) { self.name = n; self.magicNumber = m; self.shoeSize = ss; self.subThingies = [NSMutableArray array]; } return (self); } -(void) dealloc { [name release]; [subThingies release]; [super dealloc]; } //将对象编码(即:序列化) -(void) encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:name forKey:@"name"]; [aCoder encodeInt:magicNumber forKey:@"magicNumber"]; [aCoder encodeFloat:shoeSize forKey:@"shoeSize"]; [aCoder encodeObject:subThingies forKey:@"subThingies"]; } //将对象解码(反序列化) -(id) initWithCoder:(NSCoder *)aDecoder { if (self=[super init]) { self.name = [aDecoder decodeObjectForKey:@"name"]; self.magicNumber = [aDecoder decodeIntForKey:@"magicNumber"]; self.shoeSize = [aDecoder decodeFloatForKey:@"shoeSize"]; self.subThingies = [aDecoder decodeObjectForKey:@"subThingies"]; } return (self); } -(NSString*) description { NSString *description = [NSString stringWithFormat:@"%@:%d/%.1f %@",name,magicNumber,shoeSize,subThingies]; return (description); } @end
注意其中的:encodeWithCoder与initWithCoder,这是NSCoding协议中定义的二个方法,用来实现对象的编码与解码。其实现也不复杂,利用的是key-value的经典哈希结构。当然一般在编码中,对于key的名字字符串,建议用define以常量方式事先定义好,以避免开发人员字符串键入错误。
测试一下:
#import <Foundation/Foundation.h> #import "Sample.h" int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Sample *s1 = [[Sample alloc] initWithName:@"thing1" magicNumber:42 shoeSize:10.5]; [s1.subThingies addObject:@"1"]; [s1.subThingies addObject:@"2"]; NSLog(@"%@",s1); NSData *data1 = [NSKeyedArchiver archivedDataWithRootObject:s1];//将s1序列化后,保存到NSData中 [s1 release]; [data1 writeToFile:@"/tmp/data.txt" atomically:YES];//持久化保存成物理文件 NSData *data2 = [NSData dataWithContentsOfFile:@"/tmp/data.txt"];//读取文件 Sample *s2 = [NSKeyedUnarchiver unarchiveObjectWithData:data2];//反序列化 NSLog(@"%@",s2); [pool drain]; return 0; }
运行结果:
2011-03-03 14:36:48.540 pList[1322:a0f] thing1:42/10.5 (
1,
2
)
2011-03-03 14:36:48.548 pList[1322:a0f] thing1:42/10.5 (
1,
2
)
查看/tmp/data.txt,能看到以下内容:
由于经过了编码,里面的内容没有象前面的NSArray那样可读性强。