Swift 4.0 Codable
2020-03-13 本文已影响0人
jsone
一、简介
我们可以使用NSCoder
或Codable
协议来持久化数据,并使用NSKeyedArchiver
来持久化/保存,以及使用NSKeyedUnarchiver
来分别从用户文档目录获取数据。但是使用NSCoder
实现编码和解码需要你的类继承NSObject
类并实现NSCoding
协议,然而结构体就没办法继承NSObject
类,并且NSCoding
没有提供错误处理机制。于是从Swift4,Xcode 9,iOS 11开始,可以使用Encodable&Decodable
,合并后的Codable
来解决这些问题。
-
Encodable
用于编码 -
Decodable
用于解码 -
Codable
包含编码和解码
Codable
不仅支持类而且支持结构体和枚举
二、实现步骤
- 创建一个模型类,并遵守
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
}
}
- 声明
CodingKeys
枚举
private enum CodingKeys: String, CodingKey {
case name
case price
case number
case shelfLife
case remainingDays
case productionDate
case deadlineDate
}
- 实现
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)
}
- 实现商品数据模型的数组的存储和取出
// 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