iOS做存储的时候,数组里面放NSString、NSNumber、NSData等可以直接写入文件,但是我们自定义的类对象放入数组中就不能直接写入文件。原因是上述的类实现了协议,该协议有两个方法
//对对象进行归档的时候其实就是存取对象的属性
//进行编码的时候会调用,做存储操作的时候会调用这个方法
- (void)encodeWithCoder:(NSCoder *)aCoder {
}
//进行解码的时候会调用,做读取操作的时候会调用这个方法
- (id)initWithCoder:(NSCoder *)aDecoder {
}
所以我们要想实现我们自己写的类做本地存储,需要做的第一件事就是声明这个协议,再实现这个协议的方法。我们其实做存储的时候是存这个对象的属性的。
我们来实现一下基本的归档功能。
* 首先我们根据返回数据自定义一个类
.h文件
#import <Foundation/Foundation.h>
//声明<NSCoding>协议,该协议是不需要设置委托的,直接声明就行啦
@interface CollectModel : NSObject<NSCoding>
@property(nonatomic,copy) NSString *foodName;
@property(nonatomic,strong) UIImage *foodImage;
@property(nonatomic,copy) NSString *foodId;
@end
- 第二步,在.m文件里面实现该协议的两个方法
.m文件
@implementation CollectModel
#pragma mark NSCoding
//对对象进行归档的时候其实就是存取对象的属性
//进行编码的时候会调用,做存储操作的时候会调用这个方法
- (void)encodeWithCoder:(NSCoder *)aCoder {
//为每个对象设置一个key存的时候用这个key去存,取得时候也用这个key去取。
[aCoder encodeObject:self.foodName forKey:@"foodName"];
[aCoder encodeObject:self.foodId forKey:@"foodId"];
[aCoder encodeObject:self.foodImage forKey:@"foodImage"];
}
//进行解码的时候会调用,做读取操作的时候会调用这个方法
- (id)initWithCoder:(NSCoder *)aDecoder {
//因为这个方法要替换父类的init方法,我们在这里调用一下父类的init方法
self = [super init];
if (self) {
//取的时候我们也用对应的key去取
self.foodName = [aDecoder decodeObjectForKey:@"foodName"];
self.foodId = [aDecoder decodeObjectForKey:@"foodId"];
self.foodImage = [aDecoder decodeObjectForKey:@"foodImage"];
}
return self;
}
@end
- 接下来,在需要存储的地方,进行归档操作。我们会用到一个工具,叫做归档工具,这个归档工具可以认为是一把菜刀,拿这把菜刀去砍这个人,它会把这个人砍成一段一段的,然后会把这分块的人装到一个篮子里面,这个篮子叫做NSData。最终我们把这个NSData写到文件里面去,这就归档啦。
单个对象的归档
CollectModel *model = [CollectModel new];
model.foodName = @"黄瓜";
model.foodId = @"1";
model.foodImage = [UIImage imageNamed:@"1"];
//(创建篮子)创建一个可变data,用来存放归档的数据
NSMutableData *mudata = [NSMutableData new];
//(创建菜刀)创建归档工具并初始化他的可变data
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mudata];
//(砍!!!!)使用归档工具去归档某个对象,此时对象实现了NSCoding协议,就会调用的对象的encodeWithCoder对对象的属性进行归档
[archiver encodeObject:model forKey:@"huanggua"];
//结束归档操作,归档后的内容就存在了data中
[archiver finishEncoding];
//将data写入沙盒
[mudata writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:@"Documents/data.plist"] atomically:YES];
- 解归档,在我们需要从沙盒获取数据的地方,进行解归档操作
//读取沙盒中的数据
NSData *data = [NSData dataWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:@"Documents/data.plist"]];
//创建解归档工具初始化需要解归档的数据
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
//对对象进行解归档操作,此时对象实现了NSCoding协议,就会调用initWithCoder方法去解码对象的属性,key可以用一个宏定义。
CollectModel *model = [unarchiver decodeObjectForKey:@"huanggua"];
//结束解归档
[unarchiver finishDecoding];
- 将对象放入数组进行归档,做一个在本地存储收藏图片和字符串的功能。上代码!
下面我们来实现一下把服务器返回的数据存储到本地做本地收藏的功能。
- (IBAction)collectFood:(UIButton *)sender {
//创建收藏夹的model
CollectModel *collectModel = [[CollectModel alloc]init];
.
.
服务器上获取数据为collectModel的赋值,代码省略啦
.
.
//做一次解归档操作,获取沙盒中的数据,基于该数据向沙盒中添加新数据。
NSData *data = [NSData dataWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:@"Documents/data.plist"]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
//如果沙盒中没有数据,data为空,创建出来的getArr为空,注意存取的key一定要相同。
NSArray *getArr = [unarchiver decodeObjectForKey:@"arrModel"];
[unarchiver finishDecoding];
//如果getArr为空,创建出来的arr为空数组。
NSMutableArray *arr = [[NSMutableArray alloc]initWithArray:getArr];
//声明一个BOOL变量,用来判断收藏的对象在数组中是否存在。
BOOL isEqual =YES;
for (CollectModel *Model in arr) {
if ([Model.foodId isEqualToString:collectModel.foodId]) {
isEqual =NO;
}
}
NSString *notificationStr;
if (isEqual) {
//如果数组中不存在相同对象就将对象添加到数组中,如果存在相同对象就输出添加过了
[arr addObject:collectModel];
notificationStr = @"添加成功";
}
else{
notificationStr = @"你已经添加过这个啦";
}
//进行一次归档操作,将添加了对象的arr数组存入沙盒,添加后的文件会覆盖原来的文件。
NSMutableData *mudata = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mudata];
[archiver encodeObject:arr forKey:@"arrModel"];
[archiver finishEncoding];
//覆盖原来的文件
[mudata writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:@"Documents/data.plist"] atomically:YES];
//alert输出添加与否
UIAlertController *alertCon = [UIAlertController alertControllerWithTitle:@"提示" message:notificationStr preferredStyle:1];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
[alertCon addAction:cancelAction];
[self presentViewController:alertCon animated:YES completion:nil];
}
- 在收藏的视图控制器里面进行数据的展示
// 在收藏的视图控制器里面的viewWillAppear里面解归档获取数据。
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSData *data = [NSData dataWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:@"Documents/data.plist"]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
self.dataArr = [unarchiver decodeObjectForKey:@"arrModel"];
[unarchiver finishDecoding];
//获取到数据刷新表
[self.collectTableView reloadData];
}