前言:
本篇接著上一篇
iOS Swift 原生 字典數(shù)組轉(zhuǎn)模型 JSONDecoder 對(duì)象存儲(chǔ) NSKeyedArchiver
繼續(xù)寫的顷窒。
因?yàn)樵诖a里看到了一個(gè)騷操作。
這里記錄一下模型(Model)簡(jiǎn)化的寫法廓握,上次我寫模型用了 NSCoding 協(xié)議凭迹,這次不用寫這玩意了摊聋。公司大佬還是6啊偿枕。代碼之路太TM漫長(zhǎng)了璧瞬。
字典轉(zhuǎn)模型這一步?jīng)]有變化。
然后是模型在沙盒里的存取渐夸,有一點(diǎn)小小的改動(dòng)嗤锉。
Swift
代碼地址:https://github.com/gityuency/Autolayout
示例代碼類名 【SwiftCoding_2_ViewController】
運(yùn)行截圖
第一階段 回望JSON
{
"name": "農(nóng)夫果園",
"location": "上海市 浦東新區(qū) 申迪北路 753號(hào) 上海迪士尼度假區(qū)",
"number": 10001,
"money": 998.12,
"open": true,
"fruits": [
{
"name": "火龍果",
"count": 2000,
"price": 56.23,
"onsale": true
},
{
"name": "山竹",
"count": 555,
"price": 17.22,
"onsale": false
}
],
"owner": {
"name": "姬友大人",
"age": 30
}
}
第二階段 再寫Model
這次的Model不用NSCoding寫了,但是需要新增一個(gè)協(xié)議墓塌, 代碼如下:
示例的 Model:
import Foundation
/// 一個(gè)用于 model -> data 的協(xié)議
@objc protocol DataConvertible : class {
func convertToData() -> Data?
}
class FarmerModel: Codable, DataConvertible {
/// 重寫協(xié)議里的方法
func convertToData() -> Data? {
return try? JSONEncoder().encode(self)
}
/// 自己寫的方法
static func convert(from data: Data) -> FarmerModel? {
return try? JSONDecoder().decode(FarmerModel.self, from: data)
}
var name: String?
var number: Int?
var money: Float?
var open: Bool?
var address: String?
var fruits: [FarmerFruits]?
var owner: FarmerOwner?
}
/// 二級(jí)模型 水果攤
class FarmerFruits: Codable {
var name: String?
var count: Int?
var price: Float?
var onsale: Bool?
}
/// 二級(jí)模型 商店老板
class FarmerOwner: Codable {
var name: String?
var age: Int?
}
extension FarmerModel: CustomStringConvertible {
var description: String {
return """
\(String(describing: name))
\(String(describing: number))
\(String(describing: money))
\(String(describing: open))
\(String(describing: address))
\(String(describing: fruits))
\(String(describing: owner))
"""
}
}
extension FarmerFruits: CustomStringConvertible {
var description: String {
return """
\(String(describing: name))
\(String(describing: count))
\(String(describing: price))
\(String(describing: onsale))
"""
}
}
extension FarmerOwner: CustomStringConvertible {
var description: String {
return """
\(String(describing: name))
\(String(describing: age))
"""
}
}
第三階段 JSON 轉(zhuǎn) Model
這里是上一次的代碼瘟忱,沒有變化
代碼如下:
import Foundation
/// 字典轉(zhuǎn)模型工具類, 重復(fù)代碼不抽取
struct YXTransferToModel {
/// 字典轉(zhuǎn)模型
public static func toModelObject<T>(_ dictionary: Any?, to type: T.Type) -> T? where T: Decodable {
guard let dictionary = dictionary else {
print("? 傳入的數(shù)據(jù)解包失敗!")
return nil
}
if !JSONSerialization.isValidJSONObject(dictionary) {
print("? 不是合法的json對(duì)象!")
return nil
}
guard let data = try? JSONSerialization.data(withJSONObject: dictionary, options: []) else {
print("? JSONSerialization序列化失敗!")
return nil
}
guard let model = try? JSONDecoder().decode(type, from: data) else {
print("? JSONDecoder字典轉(zhuǎn)模型失敗!")
return nil
}
return model
}
/// 數(shù)組轉(zhuǎn)模型
public static func toModelArray<T>(_ array: Any?, to type: T.Type) -> [T]? where T: Decodable {
guard let array = array else {
print("? 傳入的數(shù)據(jù)解包失敗!")
return nil
}
if !JSONSerialization.isValidJSONObject(array) {
print("? 不是合法的json對(duì)象!")
return nil
}
guard let data = try? JSONSerialization.data(withJSONObject: array, options: []) else {
print("? JSONSerialization序列化失敗!")
return nil
}
guard let arrayModel = try? JSONDecoder().decode([T].self, from: data) else {
print("? JSONDecoder數(shù)組轉(zhuǎn)模型失敗!")
return nil
}
return arrayModel
}
}
第四階段 把模型存到沙盒里
這次寫了個(gè)新的類,主要是不想和以前的代碼混到一起苫幢。
代碼如下:
import Foundation
/// 把 模型對(duì)象 或者 模型數(shù)組 存到 沙盒 里面, 重復(fù)代碼不抽取
struct FarmerSaver {
static let key = "被教育了"
private static let YXFramerCache = "YXFramerCache"
/// 把 模型對(duì)象 存到 沙盒 里面
static func save(data: DataConvertible, key: String) {
guard let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
print("? 獲取沙盒目錄失敗!")
return
}
let userDirPath = URL(fileURLWithPath: docPath).appendingPathComponent(YXFramerCache)
guard (try? FileManager.default.createDirectory(at: userDirPath, withIntermediateDirectories: true, attributes: [:])) != nil else {
print("? 創(chuàng)建沙盒文件目錄失敗!")
return
}
let dataFullPath = "\(docPath)/\(YXFramerCache)/\(key)"
// 這一步直接把 model 轉(zhuǎn)換成 data
if let converted = data.convertToData() {
NSKeyedArchiver.archiveRootObject(converted, toFile: dataFullPath)
}
print("存儲(chǔ)路徑\n\(dataFullPath)")
}
/// 把 模型對(duì)象 從 沙盒 里取出來(lái)
static func loadDataWithCodable(key: String) -> Data? {
guard let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
print("? 獲取沙盒目錄失敗!")
return nil
}
let dataFullPath = "\(docPath)/\(YXFramerCache)/\(key)"
if let data = NSKeyedUnarchiver.unarchiveObject(withFile: "\(dataFullPath)") as? Data {
return data
}
return nil
}
/// 刪掉沙盒里的文件
static func removeAll() {
guard let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
print("? 獲取沙盒目錄失敗!")
return
}
let dirPath = "\(docPath)/\(YXFramerCache)"
guard ((try? FileManager.default.removeItem(atPath: dirPath)) != nil) else {
print("? 刪除文件夾失敗! / 沒有這個(gè)文件夾!")
return
}
print("? 清理成功!")
}
}
第五階段 測(cè)試代碼
讓我們?cè)俅螠y(cè)試一下代碼好不好用
ViewController 代碼如下:
import UIKit
import Alamofire
class SwiftCoding_2_ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func actionGo(_ sender: UIButton) {
let urlString = "http://www.yuency.com/yuencyDictionary.json"
Alamofire.request(urlString).responseJSON { (json) in
switch json.result {
case .success:
let farmer = YXTransferToModel.toModelObject(json.result.value, to: FarmerModel.self)
if let farmer = farmer {
FarmerSaver.save(data: farmer, key: FarmerSaver.key)
}
case .failure(let error):
print("網(wǎng)絡(luò)請(qǐng)求失敗 \(error)")
}
}
}
@IBAction func actionFetch(_ sender: UIButton) {
if let data = FarmerSaver.loadDataWithCodable(key: FarmerSaver.key), let farmer = FarmerModel.convert(from: data) {
print(farmer)
} else {
print("沒有金坷垃")
}
}
@IBAction func actionClear(_ sender: UIButton) {
FarmerSaver.removeAll()
}
}
結(jié)語(yǔ):
我說(shuō)過(guò)我不想再寫這個(gè)玩意了访诱。代碼弄人啊。去年的這個(gè)時(shí)候态坦,我在XEF寫代碼盐数。雖然活有點(diǎn)緊,但是心情還是輕松的伞梯,項(xiàng)目也比較簡(jiǎn)單,可以隨便寫的那種帚屉,就是業(yè)務(wù)邏輯煩躁了點(diǎn)谜诫,有些bug改起來(lái)費(fèi)工夫。那時(shí)候也正好是夏天攻旦,天還比較熱喻旷,在公司食堂吃飯完,就跑到大樓大廳下面的沙發(fā)上葛優(yōu)躺睡覺牢屋。也許是睡相太難看且预,被保安叫起來(lái)兩三次了槽袄。靠在沙發(fā)上的時(shí)候锋谐,對(duì)面是巨大的玻璃墻遍尺,玻璃墻的外面,是猛烈的日光和尋常的馬路涮拗,還有小樹和灌木乾戏。看著這廣闊的前景三热,總覺得......鼓择。好像我去那睡覺的次數(shù)也不多啊,一個(gè)夏天就這么悄悄地過(guò)去了就漾。也不記得忘記了什么呐能。