如何从该对象中的另一个 init 方法解码可编码对象

How to decode a codable object from another init method in that object

我在 swift 中有一个 Codable 类型,它的 init 方法接受从我无法控制的代码调用的 json Data。我可以使用此 Data 自动反序列化该对象吗?

class SomeType : Codable {
  // From this init I want to call into the auto generated `Decodable` init method 
  // with a decoder that can decode the passed in `Data`
  convenience init(data: Data) {
    // This is the imaginary code I'm looking for below
    let decoder = JSONDecoder(for: data)
    self.init(from: decoder)
  }
}

这样的事情可能吗? Codable 已经为我自动实现了 encode/decode,我想使用它 :)

请尝试使用 struct

struct SomeType: Codable {    
    init(data: Data) {
        do {
            self = try JSONDecoder().decode(SomeType.self, from: data)
        } catch {
            print(error)
        }
    }
}

现在您可以解析 data,例如,

let response = SomeType(data: data)
print(response)

是的,你可以,但是你必须将错误移交给调用者,否则你会得到一个关于没有初始化存储属性的编译器错误。

struct SomeType: Codable {

    let name : String
    let id : Int

    init(data: Data) throws {
        self = try JSONDecoder().decode(SomeType.self, from: data)
    }
}

let json = """
{"name":"Foo","id":12}
"""

let result = try! SomeType(data: Data(json.utf8))
print(result)

如果您可以使用结构,那么@vadian 的答案就有效。

如果您出于某种原因需要引用语义,您可以使用与调用方接口一致的适配器包装数据 class。

根据您希望如何处理错误(return 可选或抛出),您将实现不同的 init(data:) 方法。

如果您的调用者可以捕捉到错误,您可以这样做:

class AdapterType {
    let someType: SomeType

    init(data: Data) throws {
        self.someType = try JSONDecoder().decode(SomeType.self, from: data)
        // ... add do/catch/throw if you need to remap the error for your caller
    }
}

let jsonData = """
{"name":"Foo",\"id":12}
""".data(using: .utf8)!

let result = try? AdapterType(data: jsonData)
print("\(result?.someType.name ?? "(unset)")")

如果您的调用者不关心调用失败的原因并且可以处理 returned 可选,您可以使用可失败的初始化程序,如下所示:

class AdapterType {
    let someType: SomeType

    init?(data: Data) {
        guard let someType = try? JSONDecoder().decode(SomeType.self, from: data)
        else { return nil }

        self.someType = someType
    }
}

let jsonData = """
{"name":"Foo",\"id":12}
""".data(using: .utf8)!

let result = try? AdapterType(data: jsonData)
print("\(result?.someType.name ?? "(unset)")")