一、歸檔的基本概念
之前將數(shù)據(jù)保存本地此熬,只能是字符串庭呜、數(shù)組、字典犀忱、NSNuber募谎、BOOL等容器類對(duì)象對(duì)象,不能將所有對(duì)象都給保存阴汇,而采用歸檔能將所有的對(duì)象轉(zhuǎn)化為二進(jìn)制數(shù)據(jù)保存在文件中数冬,并通過(guò)解歸檔讓將文件里面保存的數(shù)據(jù)讀取出來(lái)
二、使用環(huán)境
之前我們給通訊錄添加一個(gè)聯(lián)系人只能是將添加的人放到一個(gè)字典中搀庶,然后將這個(gè)字典放到數(shù)組中拐纱,最終將數(shù)組寫入文件中
當(dāng)我們需要顯示這些聯(lián)系人時(shí)铜异,要從文件中將這個(gè)數(shù)組讀取出來(lái),還要將數(shù)據(jù)里面的一個(gè)個(gè)字典轉(zhuǎn)化成model,放到一個(gè)新數(shù)組里
而現(xiàn)在我們可以使用歸檔在添加的時(shí)候就將這一個(gè)個(gè)聯(lián)系人的信息轉(zhuǎn)化成model秸架,將這些model直接放到一個(gè)數(shù)組里揍庄,需要展示的時(shí)候,在從文件中讀取出來(lái)數(shù)據(jù)东抹,此時(shí)這個(gè)數(shù)組里面存放直接就是一個(gè)個(gè)model
有些應(yīng)用支持一個(gè)離線緩存蚂子,也就是說(shuō)當(dāng)手機(jī)沒(méi)聯(lián)網(wǎng)時(shí),可以將手機(jī)有網(wǎng)時(shí)的數(shù)據(jù)存放在本地缭黔,當(dāng)手機(jī)沒(méi)網(wǎng)時(shí)食茎,從本地中取出來(lái)這些數(shù)據(jù)展示
三、某個(gè)對(duì)象支持歸檔解歸檔需要滿足三個(gè)條件
1试浙、所屬的類遵守NSCoding協(xié)議
2董瞻、實(shí)現(xiàn)協(xié)議里面的歸檔方法
- (void)encodeWithCoder:(NSCoder *)aCoder
3、實(shí)現(xiàn)協(xié)議里面的解歸檔方法
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
四田巴、對(duì)系統(tǒng)的類進(jìn)行歸檔解歸檔
1钠糊、指定將對(duì)象放在哪個(gè)文件中,歸檔后的文件壹哺,后綴要求是archiver
[NSHomeDirectory() stringByAppendingPathComponent:@"data.archiver"];
2抄伍、將對(duì)象歸檔到指定的路徑中
[NSKeyedArchiver archiveRootObject:name toFile:path];
3、將歸檔后的數(shù)據(jù)提取出來(lái)
[NSKeyedUnarchiver unarchiveObjectWithFile:path];
五管宵、對(duì)自定義的類進(jìn)行歸檔與解歸檔
1截珍、讓這個(gè)類遵循<NSCoding>
2、實(shí)現(xiàn)歸檔方法,aCoder就是歸檔時(shí)傳過(guò)來(lái)的歸檔對(duì)象箩朴,對(duì)象被歸檔時(shí)會(huì)調(diào)用這個(gè)方法
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
[aCoder encodeObject:self.sex forKey:@"sex"];
}
3岗喉、實(shí)現(xiàn)解歸檔方法,對(duì)象解歸檔是會(huì)調(diào)用這個(gè)方法
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
//解歸檔時(shí)會(huì)產(chǎn)生一個(gè)Person對(duì)象炸庞,這里是給這個(gè)Person對(duì)象賦值
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
self.sex = [aDecoder decodeObjectForKey:@"sex"];
}
return self;
}
六钱床、同時(shí)將多個(gè)對(duì)象歸檔與解歸檔
1、歸檔
1)準(zhǔn)備一個(gè)可變的data對(duì)象埠居,通過(guò)歸檔對(duì)象將多個(gè)數(shù)據(jù)存在一個(gè)data對(duì)象里查牌,最終將這個(gè)data寫入文件
NSMutableData *data = [NSMutableData data];
2)archiver初始化的時(shí)候包裝一個(gè)可變的data對(duì)象
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
3)通過(guò)歸檔對(duì)象將這些數(shù)據(jù)轉(zhuǎn)化成二進(jìn)制,并保存在一個(gè)data對(duì)象里
[archiver encodeObject:name forKey:@"name"];
[archiver encodeInteger:age forKey:@"age"];
[archiver encodeObject:sex forKey:@"sex"];
4)轉(zhuǎn)化完畢滥壕,意思是結(jié)束使用歸檔對(duì)象將上面的數(shù)據(jù)保存在了data里面
[archiver finishEncoding];
5)將轉(zhuǎn)化好的data寫入文件
[data writeToFile:path atomically:YES];
2纸颜、解歸檔
1)將路徑里的二進(jìn)制數(shù)據(jù)給取出來(lái)
NSMutableData *data = [NSMutableData dataWithContentsOfFile:path];
2)將二進(jìn)制數(shù)據(jù)包裝在一個(gè)解歸檔對(duì)象中
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
3)通過(guò)解歸檔對(duì)象將二進(jìn)制數(shù)據(jù)分別給反序列化
NSString *name = [unarchiver decodeObjectForKey:@"name"];
NSInteger age = [unarchiver decodeIntegerForKey:@"age"];
NSString *sex = [unarchiver decodeObjectForKey:@"sex"];
七、練習(xí)
1绎橘、模擬網(wǎng)絡(luò)數(shù)據(jù)進(jìn)行本地緩存
1)修改新工程自帶的ViewController.h 如下
#import <UIKit/UIKit.h>
@interface ViewController : UITableViewController
@end
2)在AppDelegate.m里面自定義window,
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
[self.window makeKeyAndVisible];
//報(bào)錯(cuò)后胁孙,記得導(dǎo)入ViewController #import "ViewController.h"
self.window.rootViewController = [[UINavigationController alloc]initWithRootViewController:[[ViewController alloc]init]];
3)新建一個(gè)InfoModel類,
InfoModel.h
#import <Foundation/Foundation.h>
//對(duì)象要?dú)w檔必須要遵守NSCoding協(xié)議
@interface InfoModel : NSObject<NSCoding>
@property(nonatomic,copy) NSString *name;
@property(nonatomic,copy) NSString *phone;
@end
InfoModel.m
#import "InfoModel.h"
@implementation InfoModel
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.phone forKey:@"phone"];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.phone = [aDecoder decodeObjectForKey:@"phone"];
}
return self;
}
@end
4) ViewController.m
#import "ViewController.h"
#import "InfoModel.h"
//報(bào)錯(cuò),將課件中的MJExtension文件夾拖到工程中
#import "MJExtension.h"
//模擬服務(wù)器路徑
#define kLocalPath [NSHomeDirectory() stringByAppendingPathComponent:@"data.archiver"]
//模擬本地緩存路徑
#define kServerPath [[NSBundle mainBundle] pathForResource:@"Connect" ofType:@"plist"]
@interface ViewController ()
{
NSMutableArray *dataArray;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self loadData];
}
- (void)loadData{
//準(zhǔn)備數(shù)據(jù)
dataArray = [self fetchData];
if(dataArray == nil){
NSLog(@"請(qǐng)檢查網(wǎng)絡(luò)設(shè)置");
return;
}
[self.tableView reloadData];
}
- (NSMutableArray *)fetchData{
//1浊洞、先從服務(wù)器獲取數(shù)據(jù)
NSMutableArray *tempArray = [NSMutableArray arrayWithContentsOfFile:kServerPath];
if (tempArray == nil) {
//2冕茅、如果從服務(wù)器獲取數(shù)據(jù)失敗,則從本地緩存中讀取數(shù)據(jù)
tempArray = [NSKeyedUnarchiver unarchiveObjectWithFile:kLocalPath];
}else{
//3调违、如果從服務(wù)器獲取數(shù)據(jù)成功漓穿,則將數(shù)據(jù)通過(guò)MJExtension框架坷衍,轉(zhuǎn)化為model
tempArray = [InfoModel mj_objectArrayWithKeyValuesArray:tempArray];
//4、將最新從服務(wù)器獲取到數(shù)據(jù)保存到本地
[NSKeyedArchiver archiveRootObject:tempArray toFile:kLocalPath];
}
return tempArray;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellID = @"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellID];
}
InfoModel *model = dataArray[indexPath.row];
cell.textLabel.text = model.name;
cell.detailTextLabel.text = model.phone;
return cell;
}
@end