關鍵詞:
歸檔:數(shù)據(jù)持久化的一種方式,是將數(shù)據(jù)進行編碼序列化之后存儲的過程续滋。適用于小量數(shù)據(jù)的存儲舅锄。
解檔:對歸檔的數(shù)據(jù)進行解碼,拿到當初歸檔的數(shù)據(jù)的過程则吟。
NSCoding:A protocol that enables an object to be encoded and decoded for archiving and distribution.
一種能夠?qū)ο筮M行編碼和解碼槐臀,以實現(xiàn)歸檔和解檔案的協(xié)議,也就是說只有遵循了NSCoding這個協(xié)議才能實現(xiàn)數(shù)據(jù)的歸檔和解檔氓仲。
NSCoding 是一個簡單的協(xié)議水慨,通過 -initWithCoder: 和 encodeWithCoder:方法,遵循NSCoding協(xié)議的類可以被序列化和反序列化敬扛,這樣可以將數(shù)據(jù)歸檔到磁盤上晰洒。
沙盒、Archiver 啥箭、encode谍珊、UnArchiver、decode急侥、砌滞、NSCoder炼七、NSKeyedArchiver、NSKeyedUnarchiver布持、NSKeyedArchiverDelegate豌拙、NSKeyedUnarchiverDelegate
歸檔的缺點:歸檔的形式來保存數(shù)據(jù),只能一次性歸檔保存以及一次性解壓题暖。所以只能針對小量數(shù)據(jù)按傅,而且對數(shù)據(jù)操作比較笨拙,即如果想改動數(shù)據(jù)的某一小部分胧卤,還是需要解壓整個數(shù)據(jù)或者歸檔整個數(shù)據(jù)
實現(xiàn)過程
1唯绍、歸檔和解檔一個對象
ViewController
ViewController.m
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *person = [[Person alloc]init];
person.name = @"小明";
person.age = 23;
person.gender = GenderMan;
person.isAdult = YES;
person.labelArray = @[@"陽光",@"萌新",@"正太"];
person.car.color = [UIColor blackColor];
// 歸檔Person對象
[NSKeyedArchiver archiveRootObject:person toFile:[Person archivePath]];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// 解檔Person屬性,并打印
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:[Person archivePath]];
NSLog(@"%@",person.name);
NSLog(@"%ld",person.age);
NSLog(@"%ld",person.gender);
NSLog(@"%d",person.isAdult);
NSLog(@"%@",person.labelArray);
NSLog(@"%@",person.car.color);
}
- 為了方便測試枝誊,我們直接在viewDidLoad創(chuàng)建了一個person對象况芒,并給其屬性賦了值,之后將person這個對象進行了歸檔叶撒。
- 在touch方法里面我們解檔了person對象绝骚,然后將歸檔的屬性值打印了出來。
- 這里需要注意一下祠够,項目中根據(jù)情況压汪,有時候歸檔和解檔需要異步處理,自己添加子線程即可古瓤。
這個過程就實現(xiàn)了對一個對象的歸檔和解檔止剖,那么在Person類里面操作如下:
Person
Person.h
#import <Foundation/Foundation.h>
#import "Car.h"
typedef NS_ENUM(NSInteger,Gender){
GenderMan=1,
GenderWoman
};
@interface Person : NSObject<NSCoding>//歸檔解檔需要遵守NSCopying協(xié)議
@property (nonatomic, copy ) NSString *name;//姓名
@property (nonatomic ) Gender gender;//性別
@property (nonatomic ) NSUInteger age;//年齡
@property (nonatomic ) BOOL isAdult;//是否成年
@property (nonatomic, strong) NSArray *labelArray;//性格標簽數(shù)組
@property (nonatomic, strong) Car *car;
// 歸檔地址
+ (NSString *)archivePath;
@end
Person.m
#import "Person.h"
@implementation Person
- (void)encodeWithCoder:(NSCoder *)aCoder {
// 歸檔
// 這里的Key為了方便和減少錯誤,最好就用屬性作為Key
// 不同類型的屬性有不同的歸檔和解檔方法
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.gender forKey:@"gender"];
[aCoder encodeInteger:self.age forKey:@"age"];
[aCoder encodeBool:self.isAdult forKey:@"isAdult"];
[aCoder encodeObject:self.labelArray forKey:@"labelArray"];
// 這里注意一下落君,歸檔一個對象的時候穿香,這個對象也需要實現(xiàn)NSCoding協(xié)議和相應的方法,不然的話直接閃退绎速,閃退日志如下:
// -[Car encodeWithCoder:]: unrecognized selector sent to instance
[aCoder encodeObject:self.car forKey:@"car"];
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
// 解檔皮获,賦值
// 這里的Key需與歸檔時的Key一致
self.name = [aDecoder decodeObjectForKey:@"name"];
self.gender = [aDecoder decodeIntegerForKey:@"gender"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
self.isAdult = [aDecoder decodeBoolForKey:@"isAdult"];
self.labelArray = [aDecoder decodeObjectForKey:@"labelArray"];
self.car = [aDecoder decodeObjectForKey:@"car"];
}
return self;
}
// 歸檔地址
+ (NSString *)archivePath {
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
return [path stringByAppendingString:@"PersonCache"];
}
//通過get方法創(chuàng)建car對象,外部不再需要每次創(chuàng)建朝氓,直接使用點語法給car的屬性賦值即可魔市。
- (Car *)car {
if (!_car) {
_car = [[Car alloc]init];
}
return _car;
}
@end
- 這里的Person和Car是我們創(chuàng)建的兩個類,算是兩個Model赵哲。
- Person中有一些屬性待德,特別的它有一個屬性car。
- 歸檔需要 有一個歸檔的地址枫夺,我們直接用類方法返回一個歸檔路徑将宪。
Car
Car.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface Car : NSObject<NSCoding>//Car也需要遵循NSCoding協(xié)議
@property (nonatomic, strong) UIColor *color;//汽車顏色
@end
Car.m
#import "Car.h"
@implementation Car
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.color forKey:@"color"];
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
self.color = [aDecoder decodeObjectForKey:@"color"];
}
return self;
}
@end
- Car有一個屬性color,要想歸檔Person對象的car屬性,則需要Car也遵循NSCoding協(xié)議较坛,而且也需要實現(xiàn)自己的歸檔和解檔方法印蔗。
到這里歸檔和解檔一個對象的操作就完成了
小結(jié)
總結(jié)一下歸檔一個對象需要以下幾個步驟:
1、遵循NSCoding協(xié)議<NSCoding>
2丑勤、實現(xiàn)歸檔和解檔的方法
- (void)encodeWithCoder:(NSCoder *)aCoder
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
3华嘹、歸檔或者解檔
// 歸檔Person
[NSKeyedArchiver archiveRootObject:person toFile:[Person archivePath]];
// 解檔Person
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:[Person archivePath]];
2、歸檔一個數(shù)組法竞、字典等
與歸檔一個對象一樣的原理耙厚,這里講歸檔數(shù)組的地址寫了一個宏。
//數(shù)組歸檔地址
#define kChachArrayPath [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingString:@"MyArray"]
// 歸檔數(shù)組
NSArray *array = @[@"陽光",@"萌新",@"正太"];
[NSKeyedArchiver archiveRootObject:array toFile:kChachArrayPath];
// 解檔數(shù)組
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:kChachArrayPath];
NSLog(@"%@",array[0]);
這種只歸檔了一個數(shù)組的方式如果在項目中使用岔霸,建議不要這樣用薛躬,因為不方便管理。推薦使用NSUserDefaults呆细。根據(jù)具體的項目情況選擇最合適的型宝。