iOS Swift 原生 字典數(shù)組轉(zhuǎn)模型 JSONDecoder 對象存儲(chǔ) NSKeyedArchiver

前言:

最近在寫關(guān)于網(wǎng)絡(luò)請求相關(guān)的代碼。簡單來說,我要做的事情是:

1、創(chuàng)建一個(gè) Swift Model 類
2、通過網(wǎng)絡(luò)請求 JSON 轉(zhuǎn) Model
3、把這個(gè) Model 存到沙盒里
4、把存起來的 Model 拿出來接著用

以上4步都是使用iOS原生的代碼做的事情,不使用三方框架。
在寫代碼的時(shí)候,也遇到了一些問題。所以,做個(gè)總結(jié)。
我再也不想寫這玩意了

Swift
代碼地址:https://github.com/gityuency/Autolayout
示例代碼類名 【SwiftCodingViewController】

運(yùn)行截圖

運(yùn)行截圖1.png
運(yùn)行截圖2.png

第一階段 認(rèn)識你的JSON

我們的JSON數(shù)據(jù)長這個(gè)樣子:
第一個(gè),最外層是個(gè)字典,里面包含了 字符串類型(String),整型(Int),浮點(diǎn)型(Float),布爾(Bool),并且包含了子對象,一個(gè)數(shù)組(Array),一個(gè)字典(Dictionary),這個(gè)JSON應(yīng)該具有些許的代表性了:

{
    "name": "農(nóng)夫果園",
    "location": "上海市 浦東新區(qū) 申迪北路 753號 上海迪士尼度假區(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
    }
}

第二個(gè),最外層是個(gè)數(shù)組,數(shù)組里面也包含了 字符串類型(String),整型(Int),浮點(diǎn)型(Float),布爾(Bool):

[
    {
        "name": "蘋果??",
        "count": 8855,
        "price": 6.23,
        "onsale": false
    },
    {
        "name": "菠蘿??",
        "count": 555,
        "price": 55.22,
        "onsale": false
    },
    {
        "name": "櫻桃??",
        "count": 2567,
        "price": 100.5,
        "onsale": true
    }
]

這兩種類型的JSON串你都得解出來,所以,在下面的的代碼里面,都有對應(yīng)的解法。

第二階段 寫你的Model

在上面的JSON串中,有很多不同的數(shù)據(jù)類型,所以,在寫Model的時(shí)候,也要注意類型,還有其他細(xì)節(jié)。關(guān)于這個(gè)Model,要注意的事情我都寫在了代碼注釋里面。
存對象,NSKeyedArchiver,需要繼承 NSCoding 協(xié)議
編碼解碼,JSONDecoder,需要繼承 Codable 協(xié)議

示例的 Model:

import Foundation

class HomePageModel: NSObject, NSCoding, Codable {
    
    // 1號坑
    // 如果這個(gè)字段 "name_wrong_example" 在后端返回過來的 json 串里沒有, 而這里定義類型 是 "String" 不是 "String?" 將會(huì)導(dǎo)致在 JSONDecoder 的時(shí)候字典轉(zhuǎn)模型失敗
    // 同樣的道理, 不管定義的屬性類型是什么, 只要是在 json 串里沒有的, 不使用可選型,都會(huì)導(dǎo)致解析失敗,所以,為了安全起見,把這些屬性都定義為可選型吧
    //var name_wrong_example: String = "初始值,"  //錯(cuò)誤
    //var name_wrong_example: String? = "初始值"  //正確
    //var name_wrong_example: String?            //正確
    
    var name: String?
    
    var number: Int?
    
    // 2號坑
    // 如果這個(gè)字段 "money" 在后端返回過來的 json 串里是浮點(diǎn)類型的, 有小數(shù)點(diǎn), 那么需要定義為 Float, 如果定義為 Int, 將會(huì)導(dǎo)致 JSONDecoder 的時(shí)候字典轉(zhuǎn)模型失敗
    // 需要注意的問題是, 在json轉(zhuǎn)模型的時(shí)候, 這個(gè)字段的數(shù)值精度會(huì)丟失.
    //var money: Int? = 998      //錯(cuò)誤,定義的類型和返回的json串里的類型不一致
    //var money: Float? = 22.33  //正確 可以賦初始值
    //var money: Float?          //正確
    
    var money: Float?
    
    
    var open: Bool?

    ///"address"這個(gè)字段在 json 串里是沒有的, json 串里的 "location" 字段在這個(gè)模型里面也沒有定義, 這么做, 是為了查看 缺少字段, 寫錯(cuò)字段,會(huì)不會(huì)引起崩潰
    ///如果這里的 address 不使用 可選型, 寫成這樣: [ var address: String = "" ]  就炸了
    var address: String?
    
    // 對象里面包含了一個(gè)數(shù)組類型的值
    var fruits: [FruitsInfo]?
    
    
    // 對象里面還包含了一個(gè)對象
    var owner: OwnerInfo?
    
    
    override init() {
        
    }
    
    // NSCoding 協(xié)議里面的方法
    func encode(with aCoder: NSCoder) {
        
        aCoder.encode(name, forKey: "name")
        aCoder.encode(number, forKey: "number")
        aCoder.encode(money, forKey: "money")
        aCoder.encode(open, forKey: "open")

        aCoder.encode(fruits, forKey: "fruits")
        aCoder.encode(owner, forKey: "owner")
    }
    
    // NSCoding 協(xié)議里面的方法
    required init?(coder aDecoder: NSCoder) {
        super.init()
        
        name = (aDecoder.decodeObject(forKey: "name") as? String) ?? ""
        number = aDecoder.decodeObject(forKey: "number") as? Int
        money = aDecoder.decodeObject(forKey: "money") as? Float
        
        // 3號坑
        // 在這個(gè)方法里面, 如果解碼的方法調(diào)用不對,也是會(huì)造成失敗, 無法順利取出對象, 所有的屬性(Bool, String, Int ...), 在解碼的時(shí)候都要調(diào)用 decodeObject, 然后該轉(zhuǎn)類型的轉(zhuǎn)類型
        //open = aDecoder.decodeBool(forKey: "open") //錯(cuò)誤, 不能因?yàn)槲抑浪莃ool類型就使用 "decodeBool", 因?yàn)檫@里定義的屬性都是可選型, 同樣, 也不能使用 "decodeInteger" 這樣明確解碼類型的方法去解碼其他可選型的屬性.
        open = aDecoder.decodeObject(forKey: "open") as? Bool //正確
        
        
        fruits = aDecoder.decodeObject(forKey: "fruits") as? [FruitsInfo]
        owner = aDecoder.decodeObject(forKey: "owner") as? OwnerInfo
    }
}

/// 二級模型 水果攤
class FruitsInfo: NSObject, NSCoding, Codable {
    
    var name: String?
    var count: Int?
    var price: Float?
    var onsale: Bool?
    
    override init() {
        
    }
    
    func encode(with aCoder: NSCoder) {
        aCoder.encode(self.name, forKey: "name")
        aCoder.encode(self.count, forKey: "count")
        aCoder.encode(self.price, forKey: "price")
        aCoder.encode(self.onsale, forKey: "onsale")
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init()
        name = (aDecoder.decodeObject(forKey: "name") as? String) ?? ""
        count = aDecoder.decodeObject(forKey: "count") as? Int
        price = aDecoder.decodeObject(forKey: "price") as? Float
        onsale = aDecoder.decodeObject(forKey: "onsale") as? Bool
    }
}

/// 二級模型 商店老板
class OwnerInfo: NSObject, NSCoding, Codable {
    
    var name: String?
    var age: Int?
    
    override init() {
        
    }
    
    func encode(with aCoder: NSCoder) {
        aCoder.encode(name, forKey: "name")
        aCoder.encode(age, forKey: "age")
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init()
        name = (aDecoder.decodeObject(forKey: "name") as? String) ?? ""
        age = aDecoder.decodeObject(forKey: "age") as? Int
    }
}



extension HomePageModel {
    override 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 FruitsInfo {
    override var description: String {
        return  """
        \(String(describing: name))
        \(String(describing: count))
        \(String(describing: price))
        \(String(describing: onsale))
        """
    }
}

extension OwnerInfo {
    override var description: String {
        return  """
        \(String(describing: name))
        \(String(describing: age))
        """
    }
}

第三階段 JSON 轉(zhuǎn) Model

這個(gè)地方就要使用JSON轉(zhuǎn)Model的類了,寫來寫去就那么幾句話,但是吧,不經(jīng)常寫,還是容易尷尬。我把這些代碼寫到了一個(gè)類里面。
代碼如下:

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對象!")
            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對象!")
            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
    }
}

第三階段 (插曲) Model 轉(zhuǎn) JSON,String

這都是經(jīng)常干的事情了,JSON 和 Model 互轉(zhuǎn),所以,也寫到一起。
代碼如下:

import Foundation

/*
 來自網(wǎng)上的解釋
 
 NSJSONReadingMutableContainers:返回可變?nèi)萜?,NSMutableDictionary或NSMutableArray。
 
 NSJSONReadingMutableLeaves:返回的JSON對象中字符串的值為NSMutableString,目前在iOS 7上測試不好用,應(yīng)該是個(gè)bug,參見:
 http://stackoverflow.com/questions/19345864/nsjsonreadingmutableleaves-option-is-not-working
 
 NSJSONReadingAllowFragments:允許JSON字符串最外層既不是NSArray也不是NSDictionary,但必須是有效的JSON Fragment。例如使用這個(gè)選項(xiàng)可以解析 @“123” 這樣的字符串。參見:
 http://stackoverflow.com/questions/16961025/nsjsonserialization-nsjsonreadingallowfragments-reading
 */


/// 字典轉(zhuǎn)模型工具類,  重復(fù)代碼不抽取
struct YXTransferToJson {
    
    /// 模型轉(zhuǎn)字符串
    public static func model<T>(toString model: T) -> String? where T: Encodable {
        
        let jsonEncoder = JSONEncoder()
        jsonEncoder.outputFormatting = .prettyPrinted
        
        guard let data = try? jsonEncoder.encode(model) else {
            print("? jsonEncoder解碼失敗!")
            return nil
        }
        
        guard let jsonString = String(data: data, encoding: .utf8) else {
            print("? data到字符串失敗!")
            return nil
        }
        return jsonString
    }
    
    /// 模型轉(zhuǎn)字典
    public static func model<T>(toDictionary model: T) -> [String: Any]? where T: Encodable {
        
        let jsonEncoder = JSONEncoder()
        jsonEncoder.outputFormatting = .prettyPrinted
        
        guard let data = try? jsonEncoder.encode(model) else {
            print("? jsonEncoder解碼失敗!")
            return nil
        }
        
        guard let dictionary = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] else {
            print("? data到字典失敗!")
            return nil
        }
        return dictionary
    }
    
    /// 模型轉(zhuǎn)數(shù)組
    public static func model<T>(toArray model: T) -> [Any]? where T: Encodable {
        
        let jsonEncoder = JSONEncoder()
        jsonEncoder.outputFormatting = .prettyPrinted
        
        guard let data = try? jsonEncoder.encode(model) else {
            print("? jsonEncoder解碼失敗!")
            return nil
        }
        
        guard let array = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [Any] else {
            print("? data到數(shù)組失敗!")
            return nil
        }
        return array
    }
}

第四階段 把模型存到沙盒里

通過上面的 JSON 轉(zhuǎn) Model, 已經(jīng)拿到了 Model, 我們在斷網(wǎng)的情況下,也需要在頁面上顯示數(shù)據(jù),這就需要把 Model 存起來,先存?zhèn)€沙盒,使用 NSKeyedArchiver。
代碼如下:

import Foundation

/// 把 模型對象 或者 模型數(shù)組 存到 沙盒 里面, 重復(fù)代碼不抽取
struct YXSaverForSandBox {
    
    static let KeyCacheModelName = "取一個(gè)好聽的名字"
    
    static let KeyCacheArrayName = "你叫姬友最好聽"
    
    private static let YXModelCache = "YXModelCache" //真機(jī)下面好像不能直接使用 Document 文件夾, 會(huì)引起崩潰, 所以自己創(chuàng)建一個(gè)文件夾
    
    private static let dateFormatter = DateFormatter()
    
    /// 把 模型對象 存到 沙盒 里面
    static func saveToSandBox(key: String, with modelObject: NSCoding) {
        
        guard let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
            print("? 獲取沙盒目錄失敗!")
            return
        }
        
        let userDirPath = URL(fileURLWithPath: docPath).appendingPathComponent(YXModelCache)
        
        guard (try? FileManager.default.createDirectory(at: userDirPath, withIntermediateDirectories: true, attributes: [:])) != nil else {
            print("? 創(chuàng)建沙盒文件目錄失敗!")
            return
        }
        
        let dataFullPath = "\(docPath)/\(YXModelCache)/\(key)"
        
        NSKeyedArchiver.archiveRootObject(modelObject, toFile: dataFullPath)
    }
    
    /// 把 模型對象 從 沙盒 里取出來
    static func fetchFromSandBox<T>(key: String, asObject type: T.Type) -> T? where T: NSCoding {
        
        guard let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
            print("? 獲取沙盒目錄失敗!")
            return nil
        }
        
        let dataFullPath = "\(docPath)/\(YXModelCache)/\(key)"
        
        guard let data = NSKeyedUnarchiver.unarchiveObject(withFile: dataFullPath) as? T else {
            print("? unarchiveObject 失敗!")
            return nil
        }
        return data
    }
    
    /// 把 模型數(shù)組 存到 沙盒 里面
    static func saveToSandBox(key: String, with modelArray: [NSCoding]) {
        
        guard let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
            print("? 獲取沙盒目錄失敗!")
            return
        }
        
        let userDirPath = URL(fileURLWithPath: docPath).appendingPathComponent(YXModelCache)
        
        guard (try? FileManager.default.createDirectory(at: userDirPath, withIntermediateDirectories: true, attributes: [:])) != nil else {
            print("? 創(chuàng)建沙盒文件目錄失敗!")
            return
        }
        
        let dataFullPath = "\(docPath)/\(YXModelCache)/\(key)"
        
        NSKeyedArchiver.archiveRootObject(modelArray, toFile: dataFullPath)
    }
    
    /// 把 模型數(shù)組 從 沙盒 里取出來
    static func fetchFromSandBox<T>(key: String, asArray type: T.Type) -> [T]? where T: NSCoding {
        
        guard let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
            print("? 獲取沙盒目錄失敗!")
            return nil
        }
        
        let dataFullPath = "\(docPath)/\(YXModelCache)/\(key)"
        
        guard let data = NSKeyedUnarchiver.unarchiveObject(withFile: dataFullPath) as? [T] else {
            print("? unarchiveObject 失敗!")
            return nil
        }
        return data
    }
    
    /// 把模型存到沙盒中,使用日期區(qū)分,這樣會(huì)存很多的文件
    static func save(model: NSCoding) {
        
        let date = Date()
        dateFormatter.dateFormat = "yyyy年 MM月 dd日 HH時(shí) mm分 ss秒 SSS毫秒"
        let strDate = dateFormatter.string(from: date)
        
        guard let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
            print("? 獲取沙盒目錄失敗!")
            return
        }
        
        let userDirPath = URL(fileURLWithPath: docPath).appendingPathComponent(YXModelCache)
        
        guard (try? FileManager.default.createDirectory(at: userDirPath, withIntermediateDirectories: true, attributes: [:])) != nil else {
            print("? 創(chuàng)建沙盒文件目錄失敗!")
            return
        }
        
        let dataFullPath = "\(docPath)/\(YXModelCache)/\(strDate)"
        
        NSKeyedArchiver.archiveRootObject(model, toFile: dataFullPath)
    }
    
    /// 刪掉沙盒里的文件
    static func removeAll() {
        
        guard let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
            print("? 獲取沙盒目錄失敗!")
            return
        }
        
        let dirPath = "\(docPath)/\(YXModelCache)"
        
        guard ((try? FileManager.default.removeItem(atPath: dirPath)) != nil) else {
            print("? 刪除文件夾失敗!")
            return
        }
    }
}

第四階段(插曲) 把模型存到 UserDefaults 里

有時(shí)候吧,為了圖省事,存到 UserDefaults 里這種事情也是干得出來的,所以,把這樣的方法也寫到一起。
代碼如下:

import Foundation

/// 把 模型對象 或者 模型數(shù)組 存到 UserDefaults 里面, 重復(fù)代碼不抽取
struct YXSaverForUserDefaults {
    
    //MARK: - Key
    static let KeyHomePageModel = "KeyHomePageModel"
    
    static let KeyFruitsArray = "KeyFruitsArray"
    
    //MARK: - Model
    /// 把 模型對象 存到 UserDefaults 里面
    static func saveToUserDefaults(key: String, with modelObject: NSCoding) {
        let data = NSKeyedArchiver.archivedData(withRootObject: modelObject)
        UserDefaults.standard.set(data, forKey: key)
    }
    
    /// 把 模型對象 從 UserDefaults 里取出來
    static func fetchFromUserDefaults<T>(key: String, asObject type: T.Type) -> T? where T: NSCoding {
        
        guard let data = UserDefaults.standard.value(forKey: key) as? Data else {
            print("? 從UserDefault里解析data失敗!")
            return nil
        }
        
        guard let model = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T else {
            print("? data轉(zhuǎn)模型失敗!")
            return nil
        }
        return model
    }
    
    //MARK: - Array
    /// 把 模型數(shù)組 存到 UserDefaults 里面
    static func saveToUserDefaults(key: String, with modelArray: [NSCoding]) {
        let data = NSKeyedArchiver.archivedData(withRootObject: modelArray)
        UserDefaults.standard.set(data, forKey: key)
    }
    
    /// 把 模型數(shù)組 從 UserDefaults 里取出來
    static func fetchFromUserDefaults<T>(key: String, asArray type: T.Type) -> [T]? where T: NSCoding {
        
        guard let data = UserDefaults.standard.value(forKey: key) as? Data else {
            print("? 從UserDefault里解析data失敗!")
            return nil
        }
        
        guard let array = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [T] else {
            print("? data轉(zhuǎn)模型失敗!")
            return nil
        }
        return array
    }
    
    /// 清理數(shù)據(jù)
    static func clearCacheModel(key: String) {
        UserDefaults.standard.removeObject(forKey: key)
    }
}

第五階段 測試代碼

到這里代碼都寫得差不多了,現(xiàn)在創(chuàng)建一個(gè) ViewController,來測試并使用那些代碼。
這里我使用了 https://github.com/Alamofire/Alamofire 來發(fā)網(wǎng)絡(luò)請求,
還用了花瓶 https://www.charlesproxy.com/
的 “Map Local” 功能來Mock數(shù)據(jù)。只是為了,看起來,就像真的一樣。

ViewController 代碼如下:

import UIKit
import Alamofire

class SwiftCodingViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    /// 字典轉(zhuǎn)模型
    @IBAction func actionDicToModel(_ sender: UIButton) {
        
        let urlString = "http://www.yuency.com/yuencyDictionary.json"
        
        Alamofire.request(urlString).responseJSON { (json) in
            
            switch json.result {
                
            case .success:
                
                // 字典轉(zhuǎn)模型
                let modelObject = YXTransferToModel.toModelObject(json.result.value, to: HomePageModel.self)
                
                //模型轉(zhuǎn) json / 字典
                print("--->\n \(YXTransferToJson.model(toString: modelObject) ?? "失敗")")
                print("--->\n \(YXTransferToJson.model(toDictionary: modelObject) ?? ["失敗":"失敗"])")
                
                // 把模型 存到 userdefault 里
                YXSaverForUserDefaults.saveToUserDefaults(key: YXSaverForUserDefaults.KeyHomePageModel, with: modelObject!)
                
                // 把模型存到沙盒里
                YXSaverForSandBox.saveToSandBox(key: YXSaverForSandBox.KeyCacheModelName, with: modelObject!)
                
                // 按照日期把數(shù)據(jù)存到沙盒(會(huì)存很多這樣的文件)
                YXSaverForSandBox.save(model: modelObject!)
                
                
            case .failure(let error):
                print("網(wǎng)絡(luò)請求失敗 \(error)")
            }
        }
    }
    
    /// 數(shù)組轉(zhuǎn)模型
    @IBAction func actionArrToModel(_ sender: UIButton) {
        
        let urlString = "http://www.yuency.com/yuencyArray.json"
        
        Alamofire.request(urlString).responseJSON { (json) in
            
            switch json.result {
                
            case .success:
                
                // 數(shù)組轉(zhuǎn)模型
                let modelArray = YXTransferToModel.toModelArray(json.result.value, to: FruitsInfo.self)
                
                //模型數(shù)組轉(zhuǎn) json / Array
                print("--->\n \(YXTransferToJson.model(toString: modelArray) ?? "失敗")")
                print("--->\n \(YXTransferToJson.model(toArray: modelArray) ?? ["失敗"])")
                
                // 把模型數(shù)組 存到 userdefault 里
                YXSaverForUserDefaults.saveToUserDefaults(key: YXSaverForUserDefaults.KeyFruitsArray, with: modelArray!)
                
                // 把模型數(shù)組 存到沙盒里
                YXSaverForSandBox.saveToSandBox(key: YXSaverForSandBox.KeyCacheArrayName, with: modelArray!)
                
            case .failure(let error):
                print("網(wǎng)絡(luò)請求失敗 \(error)")
            }
        }
    }
    
    @IBAction func actionFetchDataFromUserDefault(_ sender: UIButton) {
        // 從UserDefaults取出模型
        let modelObject = YXSaverForUserDefaults.fetchFromUserDefaults(key: YXSaverForUserDefaults.KeyHomePageModel, asObject: HomePageModel.self)
        print(modelObject ?? "沒有解出來")
        
        // 從UserDefaults取出模型
        let modelArray = YXSaverForUserDefaults.fetchFromUserDefaults(key: YXSaverForUserDefaults.KeyFruitsArray, asArray: FruitsInfo.self)
        print(modelArray ?? "沒有解出來")
    }
    
    
    @IBAction func actionFetchDataFromSandBox(_ sender: UIButton) {
        //從沙盒里取出模型
        let modelObjectFromSanBox = YXSaverForSandBox.fetchFromSandBox(key: YXSaverForSandBox.KeyCacheModelName, asObject: HomePageModel.self)
        print(modelObjectFromSanBox ?? "沒有解出來")
        
        //從沙盒里取出模型數(shù)組
        let modelArrayFromSanBox = YXSaverForSandBox.fetchFromSandBox(key: YXSaverForSandBox.KeyCacheArrayName, asArray: FruitsInfo.self)
        print(modelArrayFromSanBox ?? "沒有解出來")
    }
    
    
    @IBAction func actionClearAll(_ sender: UIButton) {
        
        YXSaverForUserDefaults.clearCacheModel(key: YXSaverForUserDefaults.KeyHomePageModel)
        YXSaverForUserDefaults.clearCacheModel(key: YXSaverForUserDefaults.KeyFruitsArray)
        
        YXSaverForSandBox.removeAll()
    }
}

結(jié)語:

現(xiàn)在應(yīng)該說是前年了,好像是8月17號的樣子。天還很熱,寫代碼的時(shí)候,靠著窗子,對著大屏幕,聽著這首鬼畜 https://www.bilibili.com/video/av3816897?from=search&seid=3916296380692081353 感覺還挺亢奮。還有一首他的電音之王,貌似搜不到了。有些東西啊,再聽的時(shí)候,就覺得,年代久遠(yuǎn)了。但愿從沒聽過

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容