【iOS】數據持久化(二)之歸檔和解檔(iOS 13以后)

在之前介紹的數據存儲方法中,不管是NSUserDefaults還是plist文件都不能對自定義對象進行存儲,OC提供的解歸檔恰好解決了這個問題

本片文章對 iOS13 以后的版本 歸檔和解檔 進行介紹。老版本的解歸檔見這篇文章:【iOS】文件(對象數據)的歸檔和解檔,參考這篇文章對比學習會對解歸檔有更好的理解

目錄

    • 簡介
    • 自定義對象的單個對象歸檔、解檔
    • 多個對象解檔歸檔
    • 嵌套類(復合類)
    • 解檔 Success!!
    • 注意
    • MJExtension庫(JSONModel、YYModel)


簡介

在iOS中,對象的序列化和反序列化分別使用NSKeyedArchiverNSKeyedUnarchiver兩個類,我們可以把一個類對象進行序列化然后保存到文件中,使用時再讀取文件,把內容反序列化出來。這個過程通常也被稱為 對象的編碼(歸檔)和解碼(解檔)

  • 歸檔 — 將對象以文件(二進制數據)的形式保存到磁盤上中(也稱序列化,持久化)
  • 解檔 — 使用時從磁盤上讀取該文件的保存路徑,從而讀取文件的內容(也稱反序列化)

歸檔一般保存自定義對象、自定義對象數組,由于自定義對象不具有歸檔的性質,所以只有遵循了NSCoding協議的類才可以歸檔
由于決大多數支持存儲數據的Foundation和Cocoa Touch類都遵循了NSCoding協議,因此,對于大多數OC提供的類來說,歸檔相對而言還是比較容易實現的。

對象歸檔的文件是保密的,在磁盤上無法查看文件中的內容,而屬性列表是明文的,可以查看。通過文件歸檔產生的文件是不可見的,如果打開歸檔文件的話,內容是亂碼的;ta不同于屬性列表和plist文件是可見的,正因為不可見的緣故,使得這種持久性的數據保存更有可靠性

自定義對象的單個對象歸檔、解檔

iOS 13中需要支持NSSecureCoding 協議(父協議為NSCoding)才能支持歸檔
請添加圖片描述

  1. 自定義一個Person類并實現NSCoding 協議的方法
@interface Person : NSObject <NSSecureCoding>@property (nonatomic, copy)NSString* name;
@property (nonatomic, assign)int age;
@property (nonatomic, assign)double weight;@end@implementation Person//NSCoder是一個抽象類
//歸檔的協議方法
//將歸檔對象序列化
- (void)encodeWithCoder:(NSCoder *)coder {[coder encodeObject: self.name forKey: @"name"];[coder encodeInt: self.age forKey: @"age"];[coder encodeDouble: self.weight forKey: @"weight"];
}//解檔的協議方法
//將解檔對象反序列化
- (instancetype)initWithCoder:(NSCoder *)coder {self = [super init];if (self) {self.name = [coder decodeObjectForKey: @"name"];self.age = [coder decodeIntForKey: @"age"];self.weight = [coder decodeDoubleForKey: @"weight"];}return self;
}@end//NSSecureCoding的協議方法
+ (BOOL)supportsSecureCoding {return YES;
}
  1. 初始化待歸檔對象并進行歸檔

+ (nullable NSData *)archivedDataWithRootObject:(id)object requiringSecureCoding:(BOOL)requiresSecureCoding error:(NSError **)error;

        Person* person = [[Person alloc] init];person.name = @"XY";person.age = 20;person.weight = 125.0;//歸檔成二進制數據流NSError* error;NSData* data1 = [NSKeyedArchiver archivedDataWithRootObject: person requiringSecureCoding: YES error: &error];if (error) {NSLog(@"歸檔錯誤:%@", error);return 0;}//寫入指定路徑(一般寫入到沙盒,這里方便演示存到一個新的文件夾)[data1 writeToFile: @"/Users/jakey/Desktop/CS/Xcode/NSKeyedArchiverTest/test.archiver" atomically: YES];

Person對象被序列化后就會被保存在下方的文件中,但無法直接打開
請添加圖片描述

通過終端命令打開后,可以看到內容是經過加密的,保證了數據的安全性
請添加圖片描述

  1. 開始解檔

+ (nullable id)unarchivedObjectOfClass:(Class)cls fromData:(NSData *)data error:(NSError **)error;

        //解檔此二進制數據error = nil;NSData* data2 = [NSData dataWithContentsOfFile: @"/Users/jakey/Desktop/CS/Xcode/NSKeyedArchiverTest/test.archiver"];Person* unarchiverPerson = (Person *)[NSKeyedUnarchiver unarchivedObjectOfClass: [Person class] fromData: data2 error: &error];if (error) {NSLog(@"解檔錯誤:%@", error);}NSLog(@"unarchiverPerson:%@", unarchiverPerson);

請添加圖片描述

多個對象解檔歸檔

將多個對象歸檔在同一個文件中:

  1. 初始化待歸檔對象并進行歸檔
Person* person1 = [[Person alloc] init];
person1.name = @"XY";
person1.age = 20;
person1.weight = 125.0;
Dog* dog1 = [[Dog alloc] init];
dog1.name = @"Bruce";
person1.dog = dog1;     Person* person2 = [[Person alloc] init];
person2.name = @"Jacky";
person2.age = 21;
person2.weight = 130.0;
Dog* dog2 = [[Dog alloc] init];
dog2.name = @"Oudy";
person2.dog = dog2;//創建歸檔對象
NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding: NO];//進行歸檔(編碼)操作
[archiver encodeObject: person1 forKey: @"personOne"];
[archiver encodeObject: person2 forKey: @"personTwo"];//將歸檔(序列化)后的數據寫入指定文件中
[archiver.encodedData writeToFile: @"/Users/jakey/Desktop/CS/Xcode/NSKeyedArchiverTest/test.archiver" atomically: YES];//結束歸檔
[archiver finishEncoding];
  1. 依次解檔
//解檔
NSData* data = [NSData dataWithContentsOfFile: @"/Users/jakey/Desktop/CS/Xcode/NSKeyedArchiverTest/test.archiver"];
NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData: data error: nil];
unarchiver.requiresSecureCoding = NO;Person* unchiverPerson1 = [unarchiver decodeObjectForKey: @"personOne"];
NSLog(@"%@ %d %lf %@", unchiverPerson1.name, unchiverPerson1.age, unchiverPerson1.weight, unchiverPerson1.dog.name);
Person* unchiverPerson2 = [unarchiver decodeObjectForKey: @"personTwo"];
NSLog(@"%@ %d %lf %@", unchiverPerson2.name, unchiverPerson2.age, unchiverPerson2.weight, unchiverPerson2.dog.name);

嵌套類(復合類)

現對于Person類,設置一個自定義對象dog屬性,那么這個內層的Dog類也需要實現NSSecureCoding 協議,否則程序會崩潰:

在這里插入圖片描述
上面也提到過,OC提供的類(比如這里的name)已經遵循了此協議,因此無需手動操作,但自定義的Dog類要手動添加協議函數:

@interface Dog : NSObject <NSSecureCoding>@property (nonatomic, strong)NSString* name;@end- (void)encodeWithCoder:(NSCoder *)coder {[coder encodeObject: self.name forKey: @"dogName"];
}- (instancetype)initWithCoder:(NSCoder *)coder {self = [super init];if (self) {self.name = [coder decodeObjectForKey: @"dogName"];}return self;
}+ (BOOL)supportsSecureCoding {return YES;
}

以下是復合類解歸檔完整代碼:

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"int main(int argc, const char * argv[]) {@autoreleasepool {Person* person1 = [[Person alloc] init];person1.name = @"XY";person1.age = 20;person1.weight = 125.0;Dog* dog1 = [[Dog alloc] init];dog1.name = @"Bruce";person1.dog = dog1;Person* person2 = [[Person alloc] init];person2.name = @"Jacky";person2.age = 21;person2.weight = 130.0;Dog* dog2 = [[Dog alloc] init];dog2.name = @"Oudy";person2.dog = dog2;//創建歸檔對象NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding: NO];//進行歸檔操作[archiver encodeObject: person1 forKey: @"personOne"];[archiver encodeObject: person2 forKey: @"personTwo"];//將歸檔(序列化)后的數據寫入指定文件中[archiver.encodedData writeToFile: @"/Users/jakey/Desktop/CS/Xcode/NSKeyedArchiverTest/test.archiver" atomically: YES];//結束歸檔[archiver finishEncoding];//解檔NSData* data = [NSData dataWithContentsOfFile: @"/Users/jakey/Desktop/CS/Xcode/NSKeyedArchiverTest/test.archiver"];NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData: data error: nil];unarchiver.requiresSecureCoding = NO;Person* unchiverPerson1 = [unarchiver decodeObjectForKey: @"personOne"];NSLog(@"%@ %d %lf %@", unchiverPerson1.name, unchiverPerson1.age, unchiverPerson1.weight, unchiverPerson1.dog.name);Person* unchiverPerson2 = [unarchiver decodeObjectForKey: @"personTwo"];NSLog(@"%@ %d %lf %@", unchiverPerson2.name, unchiverPerson2.age, unchiverPerson2.weight, unchiverPerson2.dog.name);return 0;
}

運行結果如下:

請添加圖片描述

解檔 Success!!

注意

如果需要歸檔的類是某個自定義類的子類時,就需要在歸檔和解檔之前實現父類的解檔和歸檔方法:[super encodeWithCoder: coder];[super initWithCoder: coder];


MJExtension庫(JSONModel、YYModel)

其實還可以使用MJExtension第三方庫實現解歸檔,這樣就可以不用寫復雜的NSCoding協議,只需要一行代碼調用寫好的宏MJExtensionCodingImplementation就可以實現

MJExtension也和JSONModel、YYModel一樣,支持 JSON數據<->Model 的轉換同時也支持解歸檔,它們在代碼量級上、性能優化上各有優缺點,詳見這篇文章:

【YYModel,MJExtension,JSONModel對比】

具體的學習,小編日后了解!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/164838.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/164838.shtml
英文地址,請注明出處:http://en.pswp.cn/news/164838.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python Anaconda創建虛擬環境及Pycharm使用虛擬環境

目錄 前言 一、Anaconda與Pycharm 二、conda常用命令 三、Pycharm使用虛擬環境 總結 前言 我們在做開發任務時可能會創建多個項目&#xff0c;這些項目可能會依賴于不同的Python環境。比如有的用到Python3.6、有的用到Python3.7&#xff1b;有的用Pytorch開發、有的用Tens…

解決:ImportError: cannot import name ‘Sequence‘ from ‘collections‘

解決&#xff1a;ImportError: cannot import name ‘Sequence‘ from ‘collections‘ 背景 在使用之前的代碼時&#xff0c;報錯&#xff1a; File “G:\research\code\MicroDE_py\plot_bcic_iv_4_ecog_trial.py”, line 262, in from skorch.helper import predefined_spl…

Java 數據結構篇-實現單鏈表核心API

&#x1f525;博客主頁&#xff1a; 小扳_-CSDN博客 ?感謝大家點贊&#x1f44d;收藏?評論? 文章目錄 1.0 單鏈表的說明 2.0 單鏈表的創建 2.1 單鏈表 - 頭插節點 2.2 單鏈表 - 遍歷 2.2.1 使用簡單的 for/while 循環 2.2.2 實現 forEach 方法 2.2.3 實現迭代器的方法 2.…

UE5 中的computer shader使用

轉載&#xff1a;UE5 中的computer shader使用 - 知乎 (zhihu.com) 目標 通過藍圖輸入參數&#xff0c;經過Compture Shader做矩陣運算 流程 1. 新建插件 2. 插件設置 3. 聲明和GPU內存對齊的參數結構 4. 聲明Compture Shader結構 5. 參數綁定 6. 著色器實現 7. 分配 work gr…

VueRouter

路由介紹 1.思考 單頁面應用程序&#xff0c;之所以開發效率高&#xff0c;性能好&#xff0c;用戶體驗好 最大的原因就是&#xff1a;頁面按需更新 比如當點擊【發現音樂】和【關注】時&#xff0c;只是更新下面部分內容&#xff0c;對于頭部是不更新的 要按需更新&#…

Git 基本使用命令

Git 基本使用命令 下面是一些常用的 Git 基本使用命令&#xff1a; 初始化一個新的 Git 倉庫&#xff1a; git init克隆&#xff08;Clone&#xff09;一個遠程倉庫到本地&#xff1a; git clone <repository_url>添加文件或目錄到暫存區&#xff08;Staging Area&am…

微信小程序前端環境搭建

搭建微信小程序前端環境 申請小程序測試賬號 訪問路徑 使用微信掃描二維碼進行申請&#xff0c;申請成功之后&#xff0c;進入界面&#xff0c;獲取小程序ID(AppID)和秘鑰(AppSecret) 安裝微信web開發者工具 訪問路徑 選擇穩定開發的版本 需要在小程序的設置中將默認關閉…

geoserver發布tif矢量數據圖層

cesium加載上傳至geoserver的tif矢量數據_cesium加載tiff-CSDN博客 geoserver安裝及跨域問題解決方案&#xff1a;geoserver安裝及跨域問題解決方案_geoserver 跨域_1 1王的博客-CSDN博客 將TIF上傳至geoserver 啟動geoserver服務&#xff0c;并進入geoserver主頁。 1. 新建…

【物聯網產品架構】如何構建物聯網產品路線圖

面對現實吧。建立物聯網產品路線圖難度要比為“正常”技術產品制定路線圖要困難得多。 這是因為IoT產品是復雜的系統。為了創建一個工作的解決方案&#xff0c;物聯網技術棧的所有層 - 設備硬件&#xff0c;設備軟件&#xff0c;通信&#xff0c;云平臺和云應用都需要一起工作。…

Spring Cloud五大組件

Spring Cloud五大組件 Spring Cloud是分布式微服務架構的一站式解決方案&#xff0c;在Spring Boot基礎上能夠輕松搭建微服務系統的架構。 現有Spring Cloud有兩代實現&#xff1a; 一代&#xff1a;Spring Cloud Netflix&#xff0c;主要由&#xff1a;Eureka、Ribbon、Feig…

【c語言】 邏輯運算符運算規則

1.&&邏輯運算符的坑 int x0&#xff0c;y0&#xff0c;z0; z (x1) && (y2); printf("%d"&#xff0c;y);//y0;今天遇到了同學問的問題&#xff0c;為什么y輸出為0. 我第一時間也記不得&#xff0c;工作中一般不會寫這種代碼&#xff0c;但是卻不能…

Vue3 狀態管理 - Pinia

1. 什么是Pinia Pinia 是 Vue 的專屬的最新狀態管理庫 &#xff0c;是 Vuex 狀態管理工具的替代品 提供更加簡單的APl&#xff08;去掉了mutation&#xff0c;Pinia 中對state數據的修改可以直接通過action&#xff0c;Vuex中則是通過mutation)提供符合組合式風格的API&#…

筆記轉移:https://www.yuque.com/u32968635/lbk

語雀&#xff1a;https://www.yuque.com/u32968635/lbk

視頻剪輯技巧:如何高效批量轉碼MP4視頻為MOV格式

在視頻剪輯的過程中&#xff0c;經常會遇到將MP4視頻轉碼為MOV格式的情況。這不僅可以更好地編輯視頻&#xff0c;還可以提升視頻的播放質量和兼容性。對于大量視頻文件的轉碼操作&#xff0c;如何高效地完成批量轉碼呢&#xff1f;現在一起來看看云炫AI智剪如何智能轉碼&#…

Servlte+JSP企業內容管理系統

企業內容管理系統的設計與實現 1&#xff0e;系統概述: 隨著企事業單位信息化的建設&#xff0c;內聯網和外聯網之間的信息交互越來越多,優秀的內容管理系統對企業內部來說&#xff0c;能夠很好地做到信息的收集和重復利用及信息的增值利用。對于外聯網來說,內容管理系統可使…

6 Go的切片

概述 在上一節的內容中&#xff0c;我們介紹了Go的數組&#xff0c;包括&#xff1a;聲明數組、初始化數組、訪問數組元素等。在本節中&#xff0c;我們將介紹Go的切片。在Go語言中&#xff0c;數組的長度是固定的&#xff0c;不能改變&#xff0c;這在某些場景下使用不太方便。…

【C++】一文簡練總結【多態】及其底層原理&具體應用(21)

前言 大家好吖&#xff0c;歡迎來到 YY 滴C系列 &#xff0c;熱烈歡迎&#xff01; 本章主要內容面向接觸過C的老鐵 主要內容含&#xff1a; 歡迎訂閱 YY滴C專欄&#xff01;更多干貨持續更新&#xff01;以下是傳送門&#xff01; 目錄 一.多態的概念二.多態的實現1&#xff…

【C++】:拷貝構造函數與賦值運算符重載的實例應用之日期類的實現

C實現日期類 ├─屬性&#xff1a; │ ├─年份 │ ├─月份 │ └─日期 ├─方法&#xff1a; │ ├─構造函數 │ ├─拷貝構造函數 │ ├─析構函數 │ ├─設置年份 │ ├─設置月份 │ ├─設置日期 │ ├─獲取年份 │ ├─獲取月份 │ ├─獲取日期 │ ├…

websocket和mqtt

WebSocket是一種通信協議&#xff0c;它允許在瀏覽器和服務器之間建立持久連接&#xff0c;并允許雙向傳遞數據。MQTT則是一種輕量級的發布/訂閱消息傳輸協議&#xff0c;常用于物聯網(IoT)設備之間的通信。 &#xff08;1&#xff09;js能直接實現mqtt嗎&#xff0c;還是需…

已解決java.lang.IllegalStateException: Duplicate key

已解決java.lang.IllegalStateException: Duplicate key 文章目錄 報錯問題解決思路解決方法交流 報錯問題 java.lang.IllegalStateException: Duplicate key 解決思路 java.lang.IllegalStateException: Duplicate key 是由于在使用 Map 或 Set 時&#xff0c;試圖將一個已經…