obj-c中有一类对象:NSArray,NSDictionary,NSString,NSNumber,NSDate,NSData以及它们的可变版本(指NSMutableArray,NSMutableDictionary...这一类) ,都可以方便的将自身的数据以某种格式(比如xml格式)序列化后保存成本地文件。
示例代码:NSArrayTest.h
代码语言:javascript复制#import <Foundation/Foundation.h>
#define FILE_NAME @"/tmp/data.txt"
@interface NSArrayTest : NSObject {
}
-(void) Test;
@end
NSArrayTest.m
代码语言:javascript复制#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 )
如果查看/tmp/data.txt,能看到下面的内容:
代码语言:javascript复制<?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>
即NSArray默认是以xml格式来序列化对象的.
如果你用来存放数据的类是自己定义的,并不是上面这些预置的对象,那么就要借助正式协议NSCoding来实现序列化和反序列化。
比如,我们有一个自己的类Sample.h
代码语言:javascript复制#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
代码语言:javascript复制#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以常量方式事先定义好,以避免开发人员字符串键入错误。
测试一下:
代码语言:javascript复制#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那样可读性强。