Как декодировать кодируемый объект из другого метода init в этом объекте - PullRequest
1 голос
/ 09 января 2020

У меня есть тип Codable в swift с методом 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 имеет автоматически реализованное кодирование / декодирование для меня, и я хотел бы использовать его :)

Ответы [ 3 ]

2 голосов
/ 09 января 2020

Если вы можете использовать структуру, тогда ответ @ vadian сработает.

Если вам по какой-то причине нужна ссылочная семантика, вы можете обернуть свой класс данных адаптером, который соответствует интерфейсу вашего абонента.

В зависимости от того, как вы хотите обрабатывать ошибки (возвращать необязательный или throw), вы будете реализовывать различные методы init (data :).

Если ваш вызывающий может поймать ошибку, вы можете сделать что-то вроде this:

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)")")

Если вызывающему абоненту все равно, почему вызов не удался, и он может обработать возвращаемый необязательный параметр, вы можете использовать неисправный инициализатор, например:

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)")")
1 голос
/ 09 января 2020

Да, вы можете, но вы должны передать сообщение об ошибке вызывающей стороне, в противном случае вы получите ошибку компилятора о том, что не инициализированы сохраненные свойства.

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)
0 голосов
/ 09 января 2020

Попробуйте использовать 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)
...