转载

iOS 设计模式系列:Archiving – 归档模式

备忘录模式就是苹果中一种归档形式。它能够把对象转化成一种数据流,在不依赖于外部类的私有属性的情况下来存储和取出数据。你可以在 iOS 6 by Tutorials 这本书的第 16 章读到更多的相关信息。或者这里 Apple’s Archives and Serializations Programming Guide。

如何使用归档 Archiving

首先,你需要声明 Album,用 NSCoding 协议来归档数据。打开 Album.h 文件,修改 @ interface 行如下:

@interface Album : NSObject <NSCoding> 

在 Album.m 添加下面两个方法:

- (void)encodeWithCode:(NSCode *)aCoder {  [aCode encodeObject:self.year forKey:@“year”];  [aCode encodeObject:self.title forKey:@“album”];  [aCode encodeObject:self.artist forKey:@“artist”];  [aCode encodeObject:self.coverUrl forKey:@“cover_url”];  [aCode encodeObject:self.genre forKey:@“genre”]; } - (id)initWithCode:(NSCode *)aDecoder {  self = [super init];  if (self) {   _year = [aDecoder decodeObjectForKey:@“year”];   _title = [aDecoder decodeObjectForKey:@“album”];   _artist = [aDecoder decodeObjectForKey:@“artist”];   _coverUrl = [aDecoder decodeObjectForKey:@“cover_url”];   _genre = [aDecoder decodeObjectForKey:@“genre”];  }  return self; }  

当你存档这个类的实例时调用 encodeWithCoder:。相反,当你通过解档来创建一个 Album 实例时,需要调用 iniWithCode: 。就这么简单,非常强大。

现在 Album 类可以存档了,添加的代码实际上是存储和加载专辑列表的。

在 PersistencyManger.h 里添加下面方法:

- (void)saveAlbums; 

当存储专辑的时候调用些方法。

现在,在 PersistencyManger.m 里添加方法实现:

- (void)saveAlbums {     NSString *filename = [NSHomeDirectory() stringByAppendingString:@“/Document/albums.bin”];     NSData *data = [NSKeyedArchiver archivedDataWithRootObject:albums];     [data writeToFile:filename atomically:YES]; } 

NSKeyedArchiver 把专辑数组存档进一个叫 album.bin 的文件里。

当你存档的一个对象包含另一个对象的时候,存档自动递归的把子对象、子对象的子对象一并存储。在这个实例里,存储的是一个专辑实例的数组。因为数组和 Album 都支持 NSCopying 的接口,数组里的东西都会被自动存档。

现在用下面代码替换 PersistencyManger.m 里的 init 方法:

- (id)init {     self = [super init];     if (self) {     NSData *data = [NSData dataWithContentsOfFile:[NSHomeDirectory() stringByAppendString:@“/Document/albums.bin”]];     albums = [NSKeyedUnarchiver unarchiveObjectWithData:data];     if (albums == nil) {     albums = [NSMutableArray arrayWithArray:      @[[[Album alloc] initWithTitle:@"Best of Bowie" artist:@"David Bowie" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png" year:@"1992"],      [[Album alloc] initWithTitle:@"It's My Life" artist:@"No Doubt" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png" year:@"2003"],      [[Album alloc] initWithTitle:@"Nothing Like The Sun" artist:@"Sting" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png" year:@"1999"],      [[Album alloc] initWithTitle:@"Staring at the Sun" artist:@"U2" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png" year:@"2000"],      [[Album alloc] initWithTitle:@"American Pie" artist:@"Madonna" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png" year:@"2000"]]];     [self saveAlbums];     }     }     return self; }  

在新代码里,如果文件存在,NSKeyedUnarchiver 就从文件加载专辑数据。如果不存在,它就创建专辑数据,然后立即存储,为下一次启动 app 使用。

当然你也可以在 app 后台运行的时候再存储专辑数据。现在它看起来不是很有必要,但如果你在稍后添加修改专辑数据呢?你需要确保所有的数据修改都会被存储。

在 LibraryAPI.h 添加下面的方法

- (void)saveAlbums; 

因为程序的所以有服务都需要通过 LibraryAPI 提供,这就是程序为什么需要 PersistenrcyManger 来存储专辑数据。

现在在 LibraryAPI.m 中添加实现方法:

- (void)saveAlbums {     [persistencyManger saveAlbums]; } 

这里是从 LibraryAPI 调用 PersistencyManger 来存储专辑。

在 ViewController.m 文件 saveCurrentState 的后面添加下面代码:

[[LibraryAPI sharedInstance] saveAlbums];

上面的代码是每当 ViewController 存储当前状态时,使用 LibraryAPI 来存储专辑数据。

构建你的 app,检查所有的都能正确编译。

不幸的是,没有一种简单的方法来验证数据是否被正确的创建。你可以在 Finder 里检查模拟器下当前 app 的 Documents 文件夹,来看看专辑数据文件是否被创建,但是为了查看其它变化你还需要添加一些数据来改变专辑数据。

但是,为了修改数据,假使为了删除专辑而需要临时添加一个删除选项,但这个选项并不会一直在你的库中存在?此外,由于误操作,错误的删除了一个专辑,但如果给这个操作添加一个撤消选项不是很好吗?

正文到此结束
Loading...