iOS數(shù)據(jù)存儲(chǔ)之NSCoder

資源連接:

iOS數(shù)據(jù)庫存儲(chǔ)之SQL語句;

iOS數(shù)據(jù)庫存儲(chǔ)之SQLite3;

iOS數(shù)據(jù)存儲(chǔ)之文件沙盒;

iOS的本地存儲(chǔ)技術(shù)

  1. Plist文件(NSArray\NSDictionary)

    Property List单匣,屬性列表文件摇庙,它是一種用來存儲(chǔ)串行化后的對(duì)象的文件。屬性列表文件的擴(kuò)展名為.plist ,因此通常被稱為 plist文件。文件是xml格式的。
    Plist文件通常用于儲(chǔ)存用戶設(shè)置,也可以用于存儲(chǔ)捆綁的信息

  2. Preference(偏好設(shè)置\NSUserDefaults)

    用戶偏好設(shè)置,plist格式文檔朽缴,文檔存儲(chǔ)在沙盒Library/Preference下,系統(tǒng)提供[NSUserDefaults standardUserDefaults]單例類直接操作文檔

  3. NSCoder(NSKeyedArchiver\NSkeyedUnarchiver)

    本文章重點(diǎn)介紹水援。

  4. SQLite3

    數(shù)據(jù)庫密强,用于處理相對(duì)大量的數(shù)據(jù)(詳情請(qǐng)參考頂部連接)。

  5. 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:

  1. NSPortCoder 和 NSCoder還有NSUnarchiver 在Xcode8.3沒有找到對(duì)應(yīng)的累银舱,也就說iOS項(xiàng)目中,iOS10以及之前的版本中Foundation框架中并沒有對(duì)應(yīng)的類跛梗。這里我們只找到了NSKeyedarchiver和NSKeyedunarchiver
  1. 對(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í)野芒,我們可以改變它的類型。

  2. 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í)畫了張圖。

EncoderAndDecoder.png
[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ì)象類型坑填。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抛人,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子脐瑰,更是在濱河造成了極大的恐慌妖枚,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苍在,死亡現(xiàn)場(chǎng)離奇詭異绝页,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)寂恬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門续誉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人初肉,你說我怎么就攤上這事酷鸦。” “怎么了牙咏?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵臼隔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我妄壶,道長(zhǎng)摔握,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任丁寄,我火速辦了婚禮氨淌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘伊磺。我一直安慰自己盛正,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布屑埋。 她就那樣靜靜地躺著豪筝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雀彼。 梳的紋絲不亂的頭發(fā)上壤蚜,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天即寡,我揣著相機(jī)與錄音徊哑,去河邊找鬼。 笑死聪富,一個(gè)胖子當(dāng)著我的面吹牛莺丑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼梢莽,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼萧豆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起昏名,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后泞当,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挡毅,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年仑扑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了览爵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镇饮,死狀恐怖蜓竹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情储藐,我是刑警寧澤俱济,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站邑茄,受9級(jí)特大地震影響姨蝴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肺缕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一左医、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧同木,春花似錦浮梢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至洲尊,卻和暖如春远豺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坞嘀。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工躯护, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丽涩。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓棺滞,卻偏偏與公主長(zhǎng)得像裁蚁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子继准,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容