資源連接:
iOS數(shù)據(jù)庫存儲(chǔ)之SQLite3;
iOS的本地存儲(chǔ)技術(shù)
-
Plist文件(NSArray\NSDictionary)
Property List单匣,屬性列表文件摇庙,它是一種用來存儲(chǔ)串行化后的對(duì)象的文件。屬性列表文件的擴(kuò)展名為.plist ,因此通常被稱為 plist文件。文件是xml格式的。
Plist文件通常用于儲(chǔ)存用戶設(shè)置,也可以用于存儲(chǔ)捆綁的信息 -
Preference(偏好設(shè)置\NSUserDefaults)
用戶偏好設(shè)置,plist格式文檔朽缴,文檔存儲(chǔ)在沙盒Library/Preference下,系統(tǒng)提供[NSUserDefaults standardUserDefaults]單例類直接操作文檔
-
NSCoder(NSKeyedArchiver\NSkeyedUnarchiver)
本文章重點(diǎn)介紹水援。
-
SQLite3
數(shù)據(jù)庫密强,用于處理相對(duì)大量的數(shù)據(jù)(詳情請(qǐng)參考頂部連接)。
-
Core Data
SQLite數(shù)據(jù)庫的面向?qū)ο蠓庋b蜗元,體量比SQLite3大很多誓斥。
NSCoder
簡(jiǎn)介:NSCoder是個(gè)抽象類,該類提供了用于存儲(chǔ)和讀取對(duì)象和其他值的接口(在內(nèi)存和其他數(shù)據(jù)形式之間)许帐,但是必須要使用它的子類劳坑。此功能提供了歸檔的基礎(chǔ)(對(duì)象和數(shù)據(jù)項(xiàng)存儲(chǔ)在磁盤上)和分配(對(duì)象和數(shù)據(jù)項(xiàng)在不同進(jìn)程或線程之間復(fù)制)。這些目的的子類包括NSArchiver成畦,NSUnarchiver距芬,NSKeyedarchiver涝开,NSKeyedunarchiver,和NSPortCoder框仔。NSCoder的具體子類統(tǒng)稱為編碼器類和這些類的實(shí)例作為編碼對(duì)象(或簡(jiǎn)單的編碼)舀武。只能編碼值的編碼器對(duì)象稱為編碼器對(duì)象,并且只能將值解碼的對(duì)象稱為為解碼器對(duì)象离斩。
Tip:
- NSPortCoder 和 NSCoder還有NSUnarchiver 在Xcode8.3沒有找到對(duì)應(yīng)的累银舱,也就說iOS項(xiàng)目中,iOS10以及之前的版本中Foundation框架中并沒有對(duì)應(yīng)的類跛梗。這里我們只找到了NSKeyedarchiver和NSKeyedunarchiver
對(duì)象寻馏,標(biāo)量,C++數(shù)組核偿、結(jié)構(gòu)诚欠、指針、字符串漾岳,以及這些類型轰绵。它不處理跨平臺(tái)執(zhí)行不同的類型,如聯(lián)合體尼荆、void *左腔、函數(shù)指針和指針的長(zhǎng)鏈。編碼器對(duì)象將對(duì)象類型信息與數(shù)據(jù)一起存儲(chǔ)捅儒,因此從字節(jié)流中解碼的對(duì)象通常與最初編碼到流中的對(duì)象相同液样。然而,當(dāng)編碼對(duì)象時(shí)野芒,我們可以改變它的類型。
AV Foundation框架給NSCoder類添加了方法(應(yīng)該是分類方法双炕,但具體聲明在哪個(gè)文件狞悲,這里不做查找),這些方法使創(chuàng)建包括核心媒體的時(shí)間結(jié)構(gòu)的歸檔更加容易妇斤,并從中提取核心媒體檔案的時(shí)間結(jié)構(gòu)摇锋。
NSCoding
這是一個(gè)編碼協(xié)議,遵守此協(xié)議站超,并且實(shí)現(xiàn)協(xié)議方法荸恕,就可以使用NSCoder進(jìn)行編碼解碼了,Cocoa框架大部分類都遵守了此協(xié)議死相。NSArray遵守了NSSecureCoding融求,NSSecureCoding 遵守了NSCoding。因此NSArray對(duì)于列表數(shù)據(jù)編碼解碼提供了很好的支持算撮。
// 用編碼器編碼對(duì)象的時(shí)候生宛,會(huì)調(diào)用該對(duì)象的此方法
- (void)encodeWithCoder:(NSCoder *)aCoder;
// 用解碼器解碼的時(shí)候會(huì)調(diào)用該對(duì)象的此方法
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder;
Note:解碼器解碼的時(shí)候怎么判斷是哪一個(gè)類呢县昂?后面會(huì)有解釋,請(qǐng)堅(jiān)持看完陷舅。
一般情況下我們還需要提供NSCoping協(xié)議支持倒彰,協(xié)議方法如下(完全看個(gè)人需求)
-(id)copyWithZone:(NSZone *)zone {
}
基本實(shí)例
通過基本實(shí)例我們可以熟悉、總結(jié)
三個(gè)對(duì)象類
//
// XWZPerson.h
// NSCodingDemo
//
// Created by XinWeizhou on 2017/5/12.
// Copyright ? 2017年 XinWeizhou. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "XWZDog.h"
extern NSString * const kName ;
extern NSString * const kAge ;
extern NSString * const kDog ;
@interface XWZPerson : NSObject<NSCoding>
@property(nonatomic,strong) NSString *name;
@property(nonatomic,assign) NSInteger age;
@property(nonatomic,strong) XWZDog *dog;
@end
#import "XWZPerson.h"
NSString * const kName = @"name";
NSString * const kAge = @"age";
NSString * const kDog = @"dog";
@implementation XWZPerson
//+ (BOOL)supportsSecureCoding {
// return YES;
//}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
_name = [aDecoder decodeObjectForKey:kName];
_age = [aDecoder decodeIntegerForKey:kAge];
_dog = [aDecoder decodeObjectForKey:kDog];
NSLog(@"%s",__func__);
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_name forKey:kName];
[aCoder encodeInteger:_age forKey:kAge];
[aCoder encodeObject:_dog forKey:kDog];
NSLog(@"%s",__func__);
}
@end
//
// XWZDog.h
// NSCodingDemo
//
// Created by XinWeizhou on 2017/5/12.
// Copyright ? 2017年 XinWeizhou. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSString * const kName ;
extern NSString * const kAge ;
@interface XWZDog : NSObject<NSCoding>
@property(nonatomic,strong) NSString *name;
@property(nonatomic,assign) NSInteger age;
@end
#import "XWZDog.h"
@implementation XWZDog
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
_name = [aDecoder decodeObjectForKey:kName];
_age = [aDecoder decodeIntegerForKey:kAge];
NSLog(@"%s",__func__);
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_name forKey:kName];
[aCoder encodeInteger:_age forKey:kAge];
NSLog(@"%s",__func__);
}
@end
//
// XWZTool.h
// NSCodingDemo
//
// Created by XinWeizhou on 2017/5/12.
// Copyright ? 2017年 XinWeizhou. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSString * const kName ;
extern NSString * const kAge ;
@interface XWZTool : NSObject<NSCoding>
@property(nonatomic,strong) NSString *name;
@property(nonatomic,assign) NSInteger age;
@end
#import "XWZTool.h"
@implementation XWZTool
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
_name = [aDecoder decodeObjectForKey:kName];
_age = [aDecoder decodeIntegerForKey:kAge];
NSLog(@"%s",__func__);
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
NSLog(@"%s",__func__);
[aCoder encodeObject:_name forKey:kName];
[aCoder encodeInteger:_age forKey:kAge];
}
@end
多對(duì)象歸檔
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *keyedDecoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
XWZTool *tool = [XWZTool new];
tool.name = @"chuTou";
tool.age = 2;
[keyedDecoder encodeObject:tool forKey:@"tool"];
XWZPerson *person = [XWZPerson new];
person.name = @"Jack";
person.age = 28;
[keyedDecoder encodeObject:person forKey:@"person"];
[keyedDecoder finishEncoding];
XWZDog *dog = [XWZDog new];
dog.name = @"mengmeng";
dog.age = 3;
NSData *dataRoot = [NSKeyedArchiver archivedDataWithRootObject:dog];
***先注釋掉***
// [data appendData:dataRoot];
self.codeData = data;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSKeyedUnarchiver *keyedDecoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:self.codeData];
XWZTool *tool = [keyedDecoder decodeObjectForKey:@"tool"];
XWZPerson *person = [keyedDecoder decodeObjectForKey:@"person"];
XWZDog *dog = [keyedDecoder decodeObjectForKey:NSKeyedArchiveRootObjectKey];
XWZDog *dog1 = [NSKeyedUnarchiver unarchiveObjectWithData:self.codeData];
[keyedDecoder finishDecoding];
NSLog(@"\n%@\n%@\n%@\n%@",tool,person,dog,dog1);
}
打印結(jié)果
<XWZTool: 0x600000036000>
<XWZPerson: 0x600000036080>
(null)
(null)
// 當(dāng)我們把上面的一行注釋代碼***先注釋掉*** [data appendData:dataRoot];還原莱睁,打印結(jié)果如下:
(null)
(null)
(null)
(null)
看來編碼之后的data數(shù)據(jù)不能隨便改動(dòng)待讳,那怎么用它的NSKeyedArchiveRootObjectKey呢,把它當(dāng)普通的key使用仰剿,繼續(xù)往下研究创淡,看代碼
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *keyedDecoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
XWZTool *tool = [XWZTool new];
tool.name = @"chuTou";
tool.age = 2;
[keyedDecoder encodeObject:tool forKey:@"tool"];
XWZPerson *person = [XWZPerson new];
person.name = @"Jack";
person.age = 28;
[keyedDecoder encodeObject:person forKey:@"person"];
XWZDog *dog = [XWZDog new];
dog.name = @"mengmeng";
dog.age = 3;
[keyedDecoder encodeObject:dog forKey:NSKeyedArchiveRootObjectKey];
[keyedDecoder finishEncoding];
self.codeData = data;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSKeyedUnarchiver *keyedDecoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:self.codeData];
XWZTool *tool = [keyedDecoder decodeObjectForKey:@"tool"];
XWZPerson *person = [keyedDecoder decodeObjectForKey:@"person"];
XWZPerson *person1 = [keyedDecoder decodeObjectForKey:@"person"];
XWZDog *dog = [keyedDecoder decodeObjectForKey:NSKeyedArchiveRootObjectKey];
XWZDog *dog1 = [keyedDecoder decodeObjectForKey:NSKeyedArchiveRootObjectKey];
XWZDog *dog2 = [NSKeyedUnarchiver unarchiveObjectWithData:self.codeData];
[keyedDecoder finishDecoding];
NSLog(@"\n%@\n%@\n%@\n%@\n%@\n%@",tool,person,person1,dog,dog1,dog2);
}
打印結(jié)果:
<XWZTool: 0x6000000316e0>
<XWZPerson: 0x608000032500>
<XWZPerson: 0x608000032500>
<XWZDog: 0x608000032740>
<XWZDog: 0x608000032740>
<XWZDog: 0x6080000327e0>
兩個(gè)人是一樣的,三條狗有兩條是一樣的酥馍,第三條為什么不一樣辩昆。這塊真的是沒有辦法研究了,第三條狗是通過類方法解檔旨袒,而且我們也不知道汁针,rootobject和其他object的具體層次關(guān)系。那妥協(xié)的結(jié)果就是我們會(huì)用就行了砚尽。下面再巖石一個(gè)組合類型:
對(duì)象組合歸檔
// 這是一個(gè)對(duì)象之間的組合
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *keyedDecoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
XWZPerson *person = [XWZPerson new];
person.name = @"Jack";
person.age = 28;
XWZDog *dog = [XWZDog new];
dog.name = @"mengmeng";
dog.age = 3;
person.dog = dog;
[keyedDecoder encodeObject:person forKey:@"person"];
[keyedDecoder finishEncoding];
self.codeData = data;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSKeyedUnarchiver *keyedDecoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:self.codeData];
XWZTool *person = [keyedDecoder decodeObjectForKey:@"person"];
NSLog(@"person= %@",person);
}
相應(yīng)結(jié)果:
person= <XWZPerson: 0x600000037e80>
Printing description of person->_dog:
<XWZDog: 0x600000037f80>
編碼器類方法直接歸檔
XWZPerson *person = [XWZPerson new];
person.name = @"Jack";
person.age = 28;
XWZDog *dog = [XWZDog new];
dog.name = @"mengmeng";
dog.age = 3;
person.dog = dog;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person];
// NSKeyedArchiver archiveRootObject:<#(nonnull id)#> toFile:<#(nonnull NSString *)#>
self.codeData = data;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
XWZPerson *person = [NSKeyedUnarchiver unarchiveObjectWithData:self.codeData];
// [NSKeyedUnarchiver unarchiveObjectWithFile:<#(nonnull NSString *)#>];
NSKeyedUnarchiver *keyedDecoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:self.codeData];
XWZPerson *person1 = [keyedDecoder decodeObjectForKey:NSKeyedArchiveRootObjectKey];
NSLog(@"\nperson0 = %@\nperson1 = %@",person,person1);
}
// 打印結(jié)果:
person0 = <XWZPerson: 0x600000031300>
person1 = <XWZPerson: 0x60800002f700>
Printing description of person->_dog:
<XWZDog: 0x600000031400>
Printing description of person1->_dog:
<XWZDog: 0x608000030aa0>
Note:其實(shí)數(shù)據(jù)要寫入文件才算歸檔施无,前面沒有加入這么一步,只是為了代碼思路簡(jiǎn)介清晰必孤』猓看上面的的注釋掉的類方法,只是多了一步存儲(chǔ)到本地的功能敷搪。文件名后綴一般用.archiver兴想。
解碼器尋找對(duì)應(yīng)類
剛才也有拋磚,現(xiàn)在把玉拋出來赡勘。首先看一下幾個(gè)方法:
NSKeyedArchiver
// 設(shè)置NSKeyedArchiver全局的對(duì)應(yīng)類標(biāo)簽嫂便,這個(gè)標(biāo)簽會(huì)被加入到編碼Data里
+ (void)setClassName:(nullable NSString *)codedName forClass:(Class)cls;
// 設(shè)置對(duì)應(yīng)的一個(gè)編碼器的對(duì)應(yīng)類標(biāo)簽
- (void)setClassName:(nullable NSString *)codedName forClass:(Class)cls;
// 開始編碼,一個(gè)對(duì)象(objv)數(shù)據(jù)對(duì)應(yīng)一個(gè)索引值(key)
- (void)encodeObject:(nullable id)objv forKey:(NSString *)key;
// 為NSKeyedUnarchiver類標(biāo)簽設(shè)置全局的類型
NSKeyedUnarchiver
+ (void)setClass:(nullable Class)cls forClassName:(NSString *)codedName;
// 為一個(gè)編碼器的對(duì)應(yīng)標(biāo)簽設(shè)置對(duì)應(yīng)類
- (void)setClass:(nullable Class)cls forClassName:(NSString *)codedName;
- (nullable id)decodeObjectForKey:(NSString *)key;
這些方法的用處總結(jié)如有錯(cuò)誤請(qǐng)指出闸与;在網(wǎng)上找了好半天也沒有找到像樣的解釋毙替,鏈接里要么各種廣告,要么打不開践樱。最后花了一個(gè)小時(shí)總結(jié)出來厂画。又花了一個(gè)小時(shí)畫了張圖。
[NSKeyedArchiver setClassName:@"hello" forClass:[XWZPerson class]];
XWZPerson *person = [XWZPerson new];
person.name = @"Jack";
person.age = 28;
[keyedDecoder encodeObject:person forKey:@"person"];
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[NSKeyedUnarchiver setClass:[XWZDog class] forClassName:@"hello"];
NSKeyedUnarchiver *keyedDecoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:self.codeData];
XWZPerson *person = [keyedDecoder decodeObjectForKey:@"person"];
NSLog(@"person = %@",person);
// 人對(duì)象編碼之后解碼成了狗對(duì)象拷邢,打印結(jié)果:
-[XWZDog initWithCoder:]
Printing description of person:
<XWZDog: 0x60800003aac0>
Printing description of person->_name:
Jack
Printing description of person->_age:
(NSInteger) _age = 28
}
Note:這里可以看出袱院,NSKeyedUnarchiver的為類名標(biāo)簽設(shè)置類型,尤為重要,它可以改變解碼出來的對(duì)象類型坑填。