如何为可编码对象提供自定义代码功能

时间:2018-07-18 15:07:35

标签: swift nsuserdefaults codable

有一种方法可以使我的可编码结构使用 code 功能, 我面临的问题是我可以从网络对其进行编码,但不能从userdefaults进行解码。这是该结构的实现。

struct profile: Codable{
    var id: Int?
    var firstName: String?
    var lastName: String?
    var description: String?
    var gender: String?
    var birthDate: Date?
    var smoke: Bool?
    var findHouse: Bool?
    var hasRoom: Bool?
    var sociable: Int?
    var ordered: Int?
    var athlete: Int?
    var party: Int?
    var domestic:Int?
    var gamer: Int?
    var usersId: Int?
    var imageId: Int?
    var createdAt: Date?
    var updatedAt: Date?
    var image: imageModel?
    var tags: [String]?

    enum CodingKeys: String, CodingKey {
        case id
        case firstName = "first_name"
        case lastName =  "last_name"
        case description
        case gender
        case birthDate = "birth_date"
        case smoke
        case findHouse = "find_house"
        case hasRoom = "has_room"
        case sociable
        case ordered
        case athlete
        case party
        case domestic
        case gamer
        case usersId = "users_id"
        case imageId = "image_id"
        case createdAt = "created_at"
        case updatedAt = "updated_at"
        case image
        case tags
    }
    init(){

    }
    init(from decoder: Decoder) throws {
        print("going to decode from decoder showing results")
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.id = (try values.decodeIfPresent(Int.self, forKey: .id))
        print("id value \(self.id)")
        self.firstName = (try values.decodeIfPresent(String.self, forKey: .firstName))
        print("name value \(self.firstName)")
        self.lastName = (try values.decodeIfPresent(String.self, forKey: .lastName))
        print("lastname value \(lastName)")
        self.description = (try values.decodeIfPresent(String.self, forKey: .description))
        print("description value \(description)")
        self.gender = (try values.decodeIfPresent(String.self, forKey: .gender))
        print("gender value \(gender)")
        if let date = try values.decodeIfPresent(String.self, forKey: .birthDate){
            print("date value \(date)")
            self.birthDate = Date(fromString: String(date.dropLast(10)), format: .custom("yyyy-MM-dd"))
            print("after conversion \(self.birthDate)")
        }else{
            self.birthDate = nil
        }
        self.smoke = (try values.decodeIfPresent(Int.self, forKey: .smoke)) == 0 ? false : true
        print("smoke value \(smoke)")
        self.findHouse = (try values.decodeIfPresent(Int.self, forKey: .findHouse)) == 0 ? false : true
        print("findhouse value \(findHouse)")
        self.hasRoom = (try values.decodeIfPresent(Int.self, forKey: .hasRoom)) == 0 ? false : true
        print("has romm value \(hasRoom)")
        self.sociable = (try values.decodeIfPresent(Int.self, forKey: .sociable))
        print("sociable value\(sociable)")
        self.ordered = (try values.decodeIfPresent(Int.self, forKey: .ordered))
        print("orderder value \(ordered)")
        self.athlete = (try values.decodeIfPresent(Int.self, forKey: .athlete))
        print("athlete value \(athlete)")
        self.party = (try values.decodeIfPresent(Int.self, forKey: .party))
        self.domestic = (try values.decodeIfPresent(Int.self, forKey: .domestic))
        self.gamer = (try values.decodeIfPresent(Int.self, forKey: .gamer))
        self.usersId = (try values.decodeIfPresent(Int.self, forKey: .usersId))
        self.imageId = (try values.decodeIfPresent(Int.self, forKey: .imageId))
        if let date = try values.decodeIfPresent(String.self, forKey: .createdAt){
            self.createdAt = Date(fromString: String(date.dropLast(10)), format: .custom("yyyy-MM-dd"))
        }else {
            self.createdAt = nil
        }
        if let date = try values.decodeIfPresent(String.self, forKey: .updatedAt){
            self.updatedAt = Date(fromString: String(date.dropLast(10)), format: .custom("yyyy-MM-dd"))
        }else{
            self.updatedAt = nil
        }
        self.image = (try values.decodeIfPresent(imageModel.self, forKey: .image))
        self.tags = (try values.decodeIfPresent([String].self, forKey: .tags))
    }

}

这是保存到userdefaults.standard的代码:

let encoder = JSONEncoder()
    if let encoded = try? encoder.encode(requestManager.instance.user) {
        UserDefaults.standard.set(encoded, forKey: "user")
        if let json = String(data: encoded, encoding: .utf8) {
            print("reading value in userDefault \(json)")
        }
    }

所以当我尝试使用以下代码从userDefaults解码时:

let decoder = JSONDecoder()
        if let user = UserDefaults.standard.data(forKey: "user"){
            print("data for user \(user)")
            do{
                let question = try decoder.decode(profile.self, from: user)
                print("birthDate from decoder \(question.birthDate)")
                print("id from decoder \(question.id)")
                print("name from decoder \(question.firstName)")
                if question.id != nil {
                    print("the id is not Nil \(question)")
                    requestManager.instance.user = question
                }

            }catch{
                print(error.localizedDescription)
                print("el valor de birthDate in \(requestManager.instance.user.birthDate)")
            }
        }

此后,我在控制台中收到了这些消息

  

要从解码器解码。   id值可选(3)。   名称值Optional(“ Yoel”)。   无法读取数据,因为格式不正确。

我猜想是birthDate,createdAt和updatedAt字段中的日期类型。

所以我想尝试的是创建一个自定义编码器,因为在解码器中期望使用String并应返回Date值。

1 个答案:

答案 0 :(得分:0)

日期本身符合可编码协议。为什么要尝试在init(from decoder: Decoder)中自己进行一些自定义解码?您不应尝试将其解码为字符串。我只是尝试了一个非常小的实现,例如:

//: Playground - noun: a place where people can play

import Foundation

var str = "Hello, playground"

struct Person:Codable {
    var name:String
    var birthDate:Date
}
func test (){
    let pascal = Person(name: "Pascal", birthDate: Date(timeIntervalSinceNow: -26.6 * 365 * 24 * 3600))
    print(pascal)
    let encoder = JSONEncoder()
    if let encoded = try? encoder.encode(pascal) {
        UserDefaults.standard.set(encoded, forKey: "person")
    }

    let decoder = JSONDecoder()

    guard let data = UserDefaults.standard.data(forKey: "person"),
          let person = try? decoder.decode(Person.self, from: data) else {
             print("damn")
             return
    }
    print(person)
}

test()