一.属性列表
在Cocoa中,有一类名为属性列表的对象,常简写为plist。这些列表包含Cocoa知道如何操作的一组对象,即Cocoa知道如何将他们保存到文件中并进行加载。包括NSArray、NSDictionary、NSString、NSNumber、NSDate、NSData,以及他们的变体。
1.NSDate
使用[NSDate date]获得当前的日期和时间。
NSDate *date = [NSDate date];
NSLog(@"%@", date);
当然,可以获取任何时间,只要你知道那时候距离现在有多久。对于将来的时间用正的时间间隔,对于过去的时间用负的时间间隔。
NSDate *yesterday = [NSDate dateWithTimeIntervalSinceNow: -(24 * 60 * 60)];
NSLog(@"%@", yesterday);
NSDate *tomorrow = [NSDate dateWithTimeIntervalSinceNow: (24 * 60 * 60)];
NSLog(@"%@", tomorrow);
2.NSData
NSData包装了大量字节,我们可以获得数据的长度和指向字节起始位置的一个指针。如果将数据块传递给一个函数或方法,可以通过传递一个自动释放的NSData来实现,无需担心内存清除问题。
//char* 转 NSData
const char * string = "Hi, I am Hoben Wong.";
NSData *data = [NSData dataWithBytes: string length:strlen(string) + 1];
//NSString 转 data
NSString *string_NS = @"Hi, I am Hoben Wong.";
NSData *data_NS = [string_NS dataUsingEncoding: NSUTF8StringEncoding];
//NSData 转 char*
NSLog(@"%s's length is %d", [data bytes], (int)[data length]);
//NSData 转 NSString
NSString *result = [[NSString alloc] initWithData: data_NS encoding:NSUTF8StringEncoding];
NSLog(@"%@'s length is %d", result, (int)[result length]);
二.编码、解码与归档
1.为什么要用编码?
- Size过大
- 包含隐私数据
- URL本身而言,歧义...
对于最后一种比较常见,例如服务器通过截取& = 来区分你的key 和value。一旦你的参数中包含了&=则就会分割错误引起歧义从而需要编码。
2.编码与解码
采用NSCoding协议,可以使用自己的对象实现编解码功能。
//NSCoding.h
#import
@protocol NSCoding
-(void) encodeWithCoder: (NSCoder *) aCoder;
-(void) initWithCoder: (NSCoder *) aDecoder;
@end
通过采用该协议,可以实现两种功能:对象需要保存自身、对象需要加载自身。
首先,在Thingie.h中实现NSCoder协议,并声明对象内容:
//Thingie.h
#import
@interface Thingie : NSObject
{
NSString *name;
int magicNumber;
float shoeSize;
NSMutableArray *subThingies;
}
@property (copy) NSString *name;
@property int magicNumber;
@property float shoeSize;
@property NSMutableArray *subThingies;
-(id) initWithName: (NSString *) n
magicNumer: (int) mn
shoeSize: (float) ss;
@end
然后在Thingie.m中实现协议和.h文件定义的方法:
//Thingie.m
-(void) encodeWithCoder:(NSCoder *) coder
{
[coder encodeObject: name forKey: @"name"];
[coder encodeInt: magicNumber forKey: @"magicNumber"];
[coder encodeFloat: shoeSize forKey: @"shoeSize"];
[coder encodeObject: subThingies forKey: @"subThingies"];
}
-(id) initWithCoder:(NSCoder *) decoder
{
if (self = [super init]) {
self.name = [decoder decodeObjectForKey: @"name"];
self.magicNumber = [decoder decodeIntForKey: @"magicNumber"];
self.shoeSize = [decoder decodeFloatForKey: @"shoeSize"];
self.subThingies = [decoder decodeObjectForKey: @"subThingies"];
}
return self;
}
最后在main.m文件初始化Thingie
Thingie *thing1;
thing1 = [[Thingie alloc] initWithName: @"Thing1" magicNumer: 42 shoeSize: 10.5];
Thingie *another;
another = [[Thingie alloc] initWithName: @"Thing2" magicNumer: 23 shoeSize: 13.0];
[thing1.subThingies addObject: another];
another = [[Thingie alloc] initWithName: @"Thing3" magicNumer: 17 shoeSize: 9.0];
[thing1.subThingies addObject: another];
NSLog(@"%@", thing1);
3.归档与解压
NSCoder是一个抽象类,定义一些有用的方法来在对象与NSData之间来回转换。我们使用NSCoder的两个子类NSKeyedArchiver和NSKeyedUnarchiver来对对象进行归档和解压。
//归档
NSData *freezeDried;
freezeDried = [NSKeyedArchiver archivedDataWithRootObject: thing1];
archivedDataWithRootObject方法编码thing1对象。过程如下:
- 首先,它在后台创建一个NSKeyedArchiver实例
- 然后,它将NSKeyedArchiver实例传递给对象thing1的-encodeWithCoder方法。
- 当thing1编码自身的属性时,它可能对其他对象进行编码,例如字符串、数组以及我们可能输入到该数组中的任何内容。
- 整个对象集合完成对键和值的编码后,具有键值对的归档程序将所有对象扁平化为一个NSData类并将其返回。
//解压
Thingie *thing2 = [NSKeyedUnarchiver unarchiveObjectWithData: freezeDried];
NSLog(@"%@", thing2);
三.总结
可以采用NSCoding协议和实现方法来编码和解码对象:可以将自己的大量对象转换成NSData类,然后将它保存到磁盘中,并可以在以后读取它。通过这种NSData类,可以重新创建对象。