使用Swift 4中的可编码/可解码来编码/解码结构

时间:2018-10-08 12:29:32

标签: ios swift struct

我不习惯使用结构,而我知道使用结构的唯一方法就是这样……

struct UserDetails {
  let name: String
  let message: String

  init(name: String, message: String) {
    self.name = name
    self.message = message
  }
}

一旦收到namemessage的值,便像这样将它们添加到结构中...

let userDetails = UserDetails(name: theName, message: theMessage)

然后将其添加到结构类型的数组中,像这样...

self.userDetailsArray.append(userDetails) 

现在,终于,当我想获取个人名称或消息时,我就这样得到了...

let user = userDetailsArray[indexPath.row]
cell.userNameLabel.text = user.name
cell.messageLabel.text = user.message

这也很好。但是我担心的是...上面我指定的方法非常旧,因为swift提出了NSCodingCodable协议。但是我不知道如何实现它们。

希望有人可以展示如何将NSCoding/Codable协议应用于上面提到的示例...

2 个答案:

答案 0 :(得分:3)

您的代码很好。要将Codable应用于解析/存储/检索用户详细信息列表,您需要定义结构,例如波纹管,

struct UserDetails: Codable {
    let name: String
    let message: String

    enum CodingKeys: String, CodingKey {
        //Uncomment the following commentted lines, if your JSON formatted data comes with different keys like bellow
        case name       //= "user_name"
        case message    //= "user_message"
    }

    init(name: String, message: String) {
        self.name = name
        self.message = message
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
        try container.encode(message, forKey: .message)
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        message = try container.decode(String.self, forKey: .message)
    }
}

要解析来自调用网络api的响应,可以使用以下函数

func makeAPICall(){
    guard let url = URL(string: "https://www.your-web-api") else { return }
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else { return }
        do {
            let decoder = JSONDecoder()
            let userDetails = try decoder.decode([UserDetails].self, from: data)
            print(userDetails)
        } catch let err {
            print("Error", err)
        }
    }.resume()
}

要存储您的用户详细信息列表,您可以像这样编写函数

func storeUserDetails(userDetails: [UserDetails]) {
    do {
        let data = try PropertyListEncoder().encode(userDetails)
        let success = NSKeyedArchiver.archiveRootObject(data, toFile: filePath(key: "file.archive"))
        print(success ? "Successful save" : "Save Failed")
    } catch {
        print("Save Failed")
    }
}

要检索您的用户详细信息列表,请使用此功能

func retrieveUserDetails() -> [UserDetails]? {
    guard let data = NSKeyedUnarchiver.unarchiveObject(withFile: filePath(key: "file.archive")) as? Data else { return nil }
    do {
        let products = try PropertyListDecoder().decode([UserDetails].self, from: data)
        return products
    } catch {
        print("Retrieve Failed")
        return nil
    }
}

和帮助程序功能获取文件路径

func filePath(key:String) -> String {
    let manager = FileManager.default
    let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
    return (url!.appendingPathComponent(key).path)
}

一些不错的读物:

  1. Encoding and Decoding Custom Types
  2. Encoding, Decoding and Serialization in Swift 4
  3. Everything about Codable in Swift 4

答案 1 :(得分:0)

可以在互联网上找到很多示例。这是使用Codable协议的通用函数。让我们举个例子:

struct UserDetails: Codable {
  let name: String, message: String
}

现在让我们来看看gist的精彩扩展:

extension Encodable {
    func encode(with encoder: JSONEncoder = JSONEncoder()) throws -> Data {
        return try encoder.encode(self)
    }
}

extension Decodable {
    static func decode(with decoder: JSONDecoder = JSONDecoder(), from data: Data) throws -> Self {
        return try decoder.decode(Self.self, from: data)
    }
}

除了基于指定的encode的{​​{1}}和decode值之外,什么都不做。

现在,它变得更加简单,就像您只需要传递从Class接收到的data一样。

API

这是您如何使用最新的if let arrUserDetails: [UserDetails] = try? [UserDetails].decode(from: data!) { print("UserDetails \(arrUserDetails)") } Encodable协议的方法。