如何将(Swift4)init添加到Decodable协议

Edw*_*eer 3 json init swift4 codable decodable

我正在尝试创建一个Codable扩展,它能够仅使用json字符串初始化Decodable(Swift 4)对象.那应该是什么工作:

struct MyObject: Decodable {
   var title: String?
}

let myObject = MyObject(json: "{\"title\":\"The title\"}")
Run Code Online (Sandbox Code Playgroud)

我认为这意味着我应该创建一个使用Decoder调用self.init的init.这是我提出的代码:

public init?(json: String) throws {
    guard let decoder: Decoder = GetDecoder.decode(json: json)?.decoder else { return }
    try self.init(from: decoder) // Who what should we do to get it so that we can call this?
}
Run Code Online (Sandbox Code Playgroud)

该代码能够获取解码器,但是在调用init时出现编译器错误.我得到的错误是:

在self.init电话之前使用'self'

这是否意味着无法在Decodable协议中添加init?

有关完整的源代码,请参阅github上的可编码扩展

更新: 从@appzYourLive调试下面的解决方案后,我发现我与init(json:Decodable和Array上的初始化程序有冲突.我刚刚向GitHub发布了新版本的扩展.我还添加了解决方案作为这个问题的新答案.

Luc*_*tti 7

一种可能的解决方法

DecodableFromString

可能的解决方案是定义另一个协议

protocol DecodableFromString: Decodable { }
Run Code Online (Sandbox Code Playgroud)

有自己的初始化程序

extension DecodableFromString {
    init?(from json: String) throws {
        guard let data = try json.data(using: .utf8) else { return nil }
        guard let value = try? JSONDecoder().decode(Self.self, from: data) else { return nil }
        self = value
    }
}
Run Code Online (Sandbox Code Playgroud)

符合DecodableFromString

现在你需要使你的类型符合 DecodableFromString

struct Person:Codable, DecodableFromString {
    let firstName: String
    let lastName: String
}
Run Code Online (Sandbox Code Playgroud)

结果

最后给了一个JSON

let json =  """
            {
            "firstName": "Luke",
            "lastName": "Skywalker"
            }
            """
Run Code Online (Sandbox Code Playgroud)

你可以建立自己的价值

if let luke = try? Person(from: json) {
    print(luke)
}
Run Code Online (Sandbox Code Playgroud)

人(名字:"卢克",姓氏:"天行者")