Swift 4.0 Codable

2020-03-13  本文已影响0人  jsone

一、简介

我们可以使用NSCoderCodable协议来持久化数据,并使用NSKeyedArchiver来持久化/保存,以及使用NSKeyedUnarchiver来分别从用户文档目录获取数据。但是使用NSCoder实现编码和解码需要你的类继承NSObject类并实现NSCoding协议,然而结构体就没办法继承NSObject类,并且NSCoding没有提供错误处理机制。于是从Swift4,Xcode 9,iOS 11开始,可以使用Encodable&Decodable,合并后的Codable来解决这些问题。

  1. Encodable用于编码
  2. Decodable用于解码
  3. Codable包含编码和解码

Codable不仅支持类而且支持结构体和枚举

二、实现步骤

  1. 创建一个模型类,并遵守Codable协议
class ProductModel: Codable {
    open var name: String = ""// 商品名称
    open var price: Double = 0.0// 价格 单位:元
    open var number: NSInteger = 0// 数量
    open var shelfLife: NSInteger = 0// 保质期 单位:天
    open var remainingDays: NSInteger = 0// 剩余天数 单位:天
    open var productionDate: String = ""// 生产日期 格式:yyyy-MM-dd HH:mm:ss
    open var deadlineDate: String = ""// 截止日期 格式:yyyy-MM-dd HH:mm:ss
    static var filePath: String {
        let manager = FileManager.default
        let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
        print("this is the url path in the documentDirectory \(String(describing: url))")
        return (url?.appendingPathComponent("Data").path)!
    }
    
    init(name: String, price: Double, number: NSInteger, shelfLife: NSInteger, remainingDays: NSInteger, productionDate: String, deadlineDate: String) {
        self.name = name
        self.price = price
        self.number = number
        self.shelfLife = shelfLife
        self.remainingDays = remainingDays
        self.productionDate = productionDate
        self.deadlineDate = deadlineDate
    }
}
  1. 声明CodingKeys枚举
private enum CodingKeys: String, CodingKey {
    case name
    case price
    case number
    case shelfLife
    case remainingDays
    case productionDate
    case deadlineDate
}
  1. 实现Codable协议的归档和解档方法
required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    name = try container.decode(String.self, forKey: .name)
    price = try container.decode(Double.self, forKey: .price)
    number = try container.decode(NSInteger.self, forKey: .number)
    shelfLife = try container.decode(NSInteger.self, forKey: .shelfLife)
    remainingDays = try container.decode(NSInteger.self, forKey: .remainingDays)
    productionDate = try container.decode(String.self, forKey: .productionDate)
    deadlineDate = try container.decode(String.self, forKey: .deadlineDate)
}

func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(name, forKey: .name)
    try container.encode(price, forKey: .price)
    try container.encode(number, forKey: .number)
    try container.encode(shelfLife, forKey: .shelfLife)
    try container.encode(remainingDays, forKey: .remainingDays)
    try container.encode(productionDate, forKey: .productionDate)
    try container.encode(deadlineDate, forKey: .deadlineDate)
}
  1. 实现商品数据模型的数组的存储和取出
// MARK: - Public
class func storeProducts(products: [ProductModel]) -> Void {
    do {
        let data = try PropertyListEncoder().encode(products)
        let success = NSKeyedArchiver.archiveRootObject(data, toFile: filePath)
        print(success ? "Successful save" : "Save failed")
    } catch {
        print("Save failed")
    }
}

class func retrieveProducts() -> [ProductModel]? {
    guard let data = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Data else {
        return nil
    }
    do {
        let products = try PropertyListDecoder().decode([ProductModel].self, from: data)
        return products
    } catch {
        print("Retrieve failed")
        return nil
    }
    
}

注意:结构体可以在extension中实现协议Codable,而类不行

参考文章:
NSKeyedArchiver using Swift 4 Codable protocol
How to store NSCoding data using Codable
Swift – NSCoder | Codable | JSONDecoder | JSONEncoder | NSKeyedArchiver | NSKeyedUnarchiver | Serialize | Deserialize | Marshelling | Demarshelling | Parse JSON | Parse Plist

上一篇下一篇

猜你喜欢

热点阅读