美文网首页
《Objective-C基础教程》读书笔记14—文件加载与保存

《Objective-C基础教程》读书笔记14—文件加载与保存

作者: 天山雪莲_38324 | 来源:发表于2018-10-31 22:46 被阅读3次

大多数计算机程序(应用程序)在关闭时都会为用户的当前成果创建一个临时的(非永久的),可能是编辑过的图片,也可能是小说的某个章节。但无论是哪种情形,用户都会有个文件保存在磁盘上。
标准C函数库提供了函数调用来创建、读取和写入文件。
Cocoa提供了两个处理文件的通用类:属性列表和对象编码。
1.属性列表
在Cocoa中,有一类名为属性列表(property list)的对象,通常简写为plist。这些列表用来放置一些Cocoa能够处理(主要是存储到文件和从文件中加载)的对象。这些属性列表类是NSArray、NSDictionary、NSString、NSNumber、NSData和NSDate, 以及它们的可修改状态(只要它们能够拥有前缀为Mutable的类)。
1.1NSDate
1.1.1获取当前的日期和时间。
1.1.2获取与当前时间相隔一定时差的日期。


image.png
image.png

注意:第二个方法接收一个NSTimeInterval参数,该参数是一个双精度值,表示以秒为单位计数的时间间隔。通过该参数可以指定时间偏移的方式:对于将来的时间,使用时间间隔的整数;对于过去的时间,使用时间间隔的负数。
1.2NSData
将缓冲区(buffer)的数据传递给函数是C语言中常见的操作。通常是将缓冲区的指针和长度传递给某个函数。疑问:C语言也可能出现内存管理问题,如果缓冲区已经被动态分配,当它不再使用时,由谁来负责将其清除?
Cocoa提供了NSData类,该类可以包含大量字节。你可以获得数据的长度(通过-length方法)和指向字节起始位置的指针(通过-byte方法)。如果你想将数据块传递给一个函数或方法,可以通过传递一个支持自动释放的NSData来实现。


image.png
image.png
注意:上述方法中的+1用于包含C字符串所需的尾部的零字节。通过包含零字节,就可以使用%s格式的说明符输出字符串。
1.3写入和读取属性列表
集合类属性列表类(NSArray和NSDictionary)具有一个—writeToFile:atomically:方法,用于将属性列表的内容写入文件。NSString和NSData也具有writeToFile:atomically:方法,不过只能写入字符串和数据块。
如果能将数据归结为属性列表类型,则可以使用这些非常便捷的方法调用来将内容保存到磁盘中,供以后读取。这些函数的一个缺点是不会返回任何错误信息。如果无法加载文件,你只能从方法中获得一个nil指针,但无法得知出现错误的具体原因。
image.png
image.png
1.4修改对象类型
需要注意,当你使用集合类从某文件读取数据时,你无法修改数据的类型。一种解决方法是强制转换,遍历plist文件的内容并创建一个平行结构的可修改对象。不过还有另外一种方法。可以借助NSPropertyListSerialization, 它可以为存储和加载属性列表的行为添加很多你需要的设定项。
image.png
image.png

2.编码对象
你无法总是将对象信息表示为属性列表类。Cocoa具备一种将对象转换成某种格式并保存到磁盘中的机制。对象可以将他们的实例变量和其他数据编码为数据块,然后保存到磁盘中。这些数据块以后还可以读回到内存中,并且还能基于保存的数据创建新对象。这个过程被称为编码与解码,也可以叫做序列化与反序列化。
扩展:在使用Interface Builder时,如果我们从库中将对象拖到窗口,这些对象会被存储到nib文件中。换句话说,UIWindow和UITextField对象都被序列化并保存到磁盘中。当程序运行时,会将nib文件加载到内存中,对象被反序列化,新的UIWindow与UITextField对象会被创建并建立关系。
一个对象要实现序列化与反序列化的功能,应当采用NSCoding协议。通过采用该协议,可以实现两种方法。当对象需要保存自身时,就会调用-encodeWithCoder方法;
当对象需要加载自身时,就会调用-initWithCoder: 方法。
NSCoder是一个抽象类,它定义了一些有用的方法,便于对象与NSData之间的转换。有一些具体实现的NSCoder子类可以用来编码和解码对象,例如NSKeyedArchiver和NSKeyedUnarchiver。
我们一般使用NSKeyedArchiver将对象归档到NSData中。KeyedArchiver使用键/值来保存对象的信息。类的-encodeWithCoder方法会使用与每个实例变量名称相匹配的键对其进行编码。你也可以使用无规则的文字作为键来编码实例变量。保证键的名称与实例变量的名称相似有助于识别它们之间的映射关系。可以使用字面量字符串作为编码键,也可以定义(宏定义)一个常量避免录入错误,也可以使用文件的局部变量。
请注意,每种类型的encodeSomething:forKey:方法都不同。需要确保你的类型使用的是正确的编码方法。对于所有的Objective-C对象类型,都要使用encodeObject:forKey方法。如果需要恢复某个归档后的对象,可以使用decodeSomethingForKey方法。
initWithCoder:和其他init方法一样,在为对象执行操作之前,需要使用超类进行初始化。可以采用两种方式,具体取决于父类。如果父类采用了NSCoding协议,则应该调用[super initWithCoder:decoder],否则只需要调用[super init]。
当你使用decodeIntForKey:方法时,会把一个int值从decoder中取出; 当你使用decodeObjectForKey:方法时,会把一个对象从decoder中取出,如果里面还有嵌入的对象,就对对其递归调用initWithCoder: 方法。
①如果要编码的对象有可变数组的属性,我们可以将对象放入该数组,当数组被编码时,这些对象将被自动编码。NSArray中的encodeWithCoder:方法的实现会对所有对象调用encodeWithCoder方法,直到所有对象都被编码。
②如果被编码的数据中含有循环,比如对象的数组属性中包含了对象自身,而对象自身又有数组属性,数组里面有对象。Cocoa的归档和反归档实现非常智能,对象循环也可以进行保存和恢复。
注意:以上所说的两种情况都已经过程序验证。
编码和解码


image.png
归档和解档
2141443C-2146-4FE3-8EB9-6DAF697F2285.png
image.png
NSLog不够智能,不能检测对象循环。
Cocoa提供了两种方式来加载和保存文件: 属性列表以及对象编码。属性列表数据类型是一种集合类,它知道如何加载和保存自身。如果对象集合中的对象类型全为属性列表,可以使用这种便捷的函数将它们保存到磁盘中,或者从磁盘中读出。如果你拥有自己的对象,而这些对象又不是属性列表类型,可以采用NSCoding协议和实现方法来编码和解码对象:将大量对象转换成NSData,然后保存到磁盘中供以后读取。通过这种NSData,可以重新创建对象。

相关文章

网友评论

      本文标题:《Objective-C基础教程》读书笔记14—文件加载与保存

      本文链接:https://www.haomeiwen.com/subject/hliztqtx.html