Objective-C基础教程学习笔记(十五)文件加载与保存
Cocoa提供了两个通用的文件处理类:属性列表和对象编码。
属性列表
在Cocoa中,有一类名为属性列表的对象,常简写为plist。这些列表包含Cocoa知道如何操作的一组对象。具体来讲,Cocoa知道如何将它们保存到文件中并进行加载。属性列表类包括NSArray、NSDictionary、NSString、NSNumber、NSDate和NSData,以及它们的变体。
NSDate
程序中经常要处理时间和日期。NSDate是Cocoa中用于处理时间和日期的基础类。
可以使用[NSDate date]获取当前的日期和时间,它是一个自动释放对象。
NSDate *date = [NSDate date];
NSLog(@”today is %@”,date);
输出:today is 2012-10-15 10:21:22 -0400
你可以使用一些方法比较两个日期,从而对列表进行排序。还可以获取与当前时间相隔一定时差的日期。例如,你可能需要24小时之前的确切日期:
NSDate *yesterday = [NSDate dateWithTimeIntervalSinceNow:-(24 * 60 * 60)];
NSLog(@”yesterday is %@”,yesterday);
+dateWithTimeIntervalSinceNow:接受一个NSTimeInterval参数,该参数是一个双精度值,表示以秒为单位的时间间隔。通过该参数可以指定时间偏移的方式:对于将来的时间,使用正的时间间隔;对于过去的时间,使用负的时间间隔。
NSData
将数据缓冲区传递给函数是C中的常见操作。为此,你通常将缓冲区的指针和长度传递给某个函数。另外,C语言中可能会出现内存管理问题。例如,如果缓冲区已经被动态分配,那么当它不再使用时,由方便负责将其清除?
Cocoa为我们提供了NSData类,该类包装了大量字节。你可以获得数据的长度和指向字节起始位置的指针。因为NSData是一个对象,适用于常规的内存管理行为。因此,如果将数据块传递给一个函数或方法,可以通过传递一个自动释放NSData来实现,无需担心内存清除问题。下面的NSData对象将保存一个普通的C字符串,然后输出数据:
const char *string = “Hi there ,this is a C string!”;
NSData *data = [NSData dataWithBytes:string length:strlen(string) +1];
NSLog(@”data is %@”,data);
NSLog(@”%d byte string is ‘%s’”,[data length],[data bytes]);
NSData对象是不可变的。它们被创建后就不能改变。可以使用它们,但是不能更改其中的内容。但是,NSMutableData支持在数据内容中添加和删除字节。
写入和读取属性列表
集合属性列表类(NSArray、NSDictionary)具有一个-writeToFile:atomically:方法,用于将属性列表写入文件。NSString和NSData也具有writeToFile:atomically:方法,但它只能写出字符串或数据块。
因此,我们可以将字符串存入一个数组,然后保存该数组:
NSArray *phrase;
phrase = [NSArray arrayWithObjects:@”I”,@”seem”,@”to”,@”be”,@”a”,@”verb”,nil];
[phrase writeToFiel:@”/tmp/verbiage.txt” atomically:YES];
现在看一下文件/tmp/veribiage.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>I</string>
<string>seem</string>
<string>to</string>
<string>be</string>
<string>a</string>
<string>verb</string>
</array>
</plist>
现在已将verbiage.txt文件存放在磁盘上,可以使用+arrayWithContentOfFile:方法读取该文件。代码如下所示:
NSArray *phrase2 = [NSArray arrayWithContentOfFile:@”/tmp/verbiage.txt”];
NSLog(“@”%@”,phrase2);
writeToFile:方法中的atomically。这个参数的值为BOOL类型,用于通知Cocoa是否应该首先将文件内容保存在临时文件中,当文件成功保存后,再将临时文件和原始文件交换。这是一种安全机制:如果在保存过程中出现意外,不会破坏原始文件。但是这种安全机制需要付出一定的代码:在保存过程中,由于原始文件仍然保存在磁盘中,所以需要使用双倍的磁盘空间。除非保存的文件非常大,将会占用用户硬盘的空间,否则应该自动保存文件。
如果能将数据精简为属性列表类型,则可以使用这些非常便捷的调用 来将内容保存到磁盘中,供以后读取。如果你正在从事一项新创意或设计一个新项目,可以使用这些便捷方法来快速编写和运行程序。即使只想把数据块保存在磁盘中,并且根本不需要使用对象,也可以使用NSData来简化工作。只需将数据包装在一个NSData对象中,然后在NSData对象上调用writeToFile:atomically:.
这些函数的一个缺点是,它们不会返回任何错误信息。如果不能加载文件,只能从方法中得到nil指针,而不能确定出现了何种错误。
编码对象
遗憾的是,无法总是将对象信息表示为属性列表类。如果能将所有对象都表示为数组字典,我们就没有必要使用自己的类了。所幸,Cocoa具备一种机制来将对象自身转换为某种格式并保存到磁盘中。对象可以将它们的实例变量和其它数据编码为数据块,然后保存到磁盘中。以后将这些数据块读回到内存中,并且还能基于保存的数据创建新对象。这个过程称为编码和解码,或称为序列化和反序列化。