obj-c中有一类对象:NSArray,NSDictionary,NSString,NSNumber,NSDate,NSData以及它们的可变版本(指NSMutableArray,NSMutableDictionary...这一类) ,都可以方便的将自身的数据以某种格式(比如xml格式)序列化后保存成本地文件。
示例代码:NSArrayTest.h
1 |
#import <Foundation/Foundation.h> |
2 |
#define FILE_NAME @"/tmp/data.txt" |
4 |
@interface NSArrayTest : NSObject { |
NSArrayTest.m
01 |
#import "NSArrayTest.h" |
03 |
@implementation NSArrayTest |
07 |
NSArray *arr = [ NSArray arrayWithObjects:@ "one" ,@ "two" ,@ "three" , nil ]; |
08 |
[arr writeToFile:FILE_NAME atomically: YES ]; |
10 |
NSArray *arr2 = [ NSArray arrayWithContentsOfFile:FILE_NAME]; |
运行结果:
2011-03-03 14:20:01.501 pList[1246:a0f] (
one,
two,
three
)
如果查看/tmp/data.txt,能看到下面的内容:
1 |
<? xml version = "1.0" encoding = "UTF-8" ?> |
即NSArray默认是以xml格式来序列化对象的.
如果你用来存放数据的类是自己定义的,并不是上面这些预置的对象,那么就要借助正式协议NSCoding来实现序列化和反序列化。
比如,我们有一个自己的类Sample.h
01 |
#import <Foundation/Foundation.h> |
03 |
@interface Sample : NSObject < NSCoding > { |
08 |
NSMutableArray *subThingies; |
11 |
@property ( copy ) NSString * name; |
12 |
@property int magicNumber; |
13 |
@property float shoeSize; |
14 |
@property (retain) NSMutableArray *subThingies; |
17 |
-( id ) initWithName:( NSString *)n magicNumber:( int )m shoeSize:( float ) ss; |
这里我们定义几个不同类型的属性,有字符串,有整数,有浮点数,还有一个可变长的数组对象
Sample.m
03 |
@implementation Sample |
06 |
@synthesize magicNumber; |
08 |
@synthesize subThingies; |
10 |
-( id ) initWithName:( NSString *)n magicNumber:( int )m shoeSize:( float )ss |
12 |
if ( self =[ super init]) |
17 |
self .subThingies = [ NSMutableArray array]; |
25 |
[subThingies release]; |
30 |
-( void ) encodeWithCoder:( NSCoder *)aCoder |
32 |
[aCoder encodeObject:name forKey:@ "name" ]; |
33 |
[aCoder encodeInt:magicNumber forKey:@ "magicNumber" ]; |
34 |
[aCoder encodeFloat:shoeSize forKey:@ "shoeSize" ]; |
35 |
[aCoder encodeObject:subThingies forKey:@ "subThingies" ]; |
39 |
-( id ) initWithCoder:( NSCoder *)aDecoder |
41 |
if ( self =[ super init]) |
43 |
self .name = [aDecoder decodeObjectForKey:@ "name" ]; |
44 |
self .magicNumber = [aDecoder decodeIntForKey:@ "magicNumber" ]; |
45 |
self .shoeSize = [aDecoder decodeFloatForKey:@ "shoeSize" ]; |
46 |
self .subThingies = [aDecoder decodeObjectForKey:@ "subThingies" ]; |
53 |
-( NSString *) description |
55 |
NSString *description = [ NSString stringWithFormat:@ "%@:%d/%.1f %@" ,name,magicNumber,shoeSize,subThingies]; |
注意其中的:encodeWithCoder与initWithCoder,这是NSCoding协议中定义的二个方法,用来实现对象的编码与解码。其实现也不复杂,利用的是key-value的经典哈希结构。当然一般在编码中,对于key的名字字符串,建议用define以常量方式事先定义好,以避免开发人员字符串键入错误。
测试一下:
01 |
#import <Foundation/Foundation.h> |
04 |
int main ( int argc, const char * argv[]) { |
05 |
NSAutoreleasePool * pool = [[ NSAutoreleasePool alloc] init]; |
07 |
Sample *s1 = [[Sample alloc] initWithName:@ "thing1" magicNumber:42 shoeSize:10.5]; |
08 |
[s1.subThingies addObject:@ "1" ]; |
09 |
[s1.subThingies addObject:@ "2" ]; |
11 |
NSData *data1 = [ NSKeyedArchiver archivedDataWithRootObject:s1]; |
13 |
[data1 writeToFile:@ "/tmp/data.txt" atomically: YES ]; |
15 |
NSData *data2 = [ NSData dataWithContentsOfFile:@ "/tmp/data.txt" ]; |
16 |
Sample *s2 = [ NSKeyedUnarchiver unarchiveObjectWithData:data2]; |
运行结果:
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那样可读性强。
这里还有篇文章,直接写了个NSData分类,可以序列化所有类,非常方便
http://www.cocoachina.com/bbs/read.php?tid=35028&keyword=%D0%F2%C1%D0%BB%AF