如何从 Codable 结构中捕获 init(from decoder:Decoder) 中的错误?

How to do-catch error in init(from decoder:Decoder) from a Codable struct?

let jsonString = """
                    {
                        "name":1,
                        "gender":"male",
                    }
                    """

struct Person: Codable {
    var name: String
    var gender: String

    public init(from decoder: Decoder) throws {
        do {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            name = try container.decode(String.self, forKey: .name)
            gender = try container.decode(String.self, forKey: .gender)
        } catch {
            print("XXXXXX \(error)")
        }
    }
}

从上面的代码来看,它不会编译,因为它会抱怨,

Return from initializer without initializing all stored properties.

我想抛出一些错误,但如果没有,我该怎么做,

  1. 为每个属性设置默认值。
  2. 将它们全部设为可选。

您不需要 init(from decoder: Decoder) 中的 do-catch,因为它已被标记为 throws。所以就这样做:

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

无论解码如何,都可以使用 do-catch 查看上述 init(from:) 方法中抛出的任何异常,如下例所示:

struct Person: Codable {
    var name: String
    var gender: String

    // Note: This is not a very good example because this init method
    // is not even necessary in this case, since the automatically-
    // synthesized `init(from:)` method does exactly the same thing. I've
    // left it here to illustrate that you don't need to have a `do-catch`
    // in this method and can instead just use `try`, since the method
    // is marked as `throws`.
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        gender = try container.decode(String.self, forKey: .gender)
    }
}

class PersonDecoder {
    func person(decodedFrom data: Data) -> Person? {
        do {
            // The `JSONDecoder.decode(_:from:)` method calls
            // `Person.init(from:)`, which can throw, which is why
            // `JSONDecoder.decode(_:from:)` also throws.
            let person = try JSONDecoder().decode(Person.self, from: data)
            return person
        } catch {
            // Inspect any thrown errors here.
            print(error)

            return nil
        }
    }
}

let personData = Data("""
{
    "name": 1,
    "gender": "male"
}
""".utf8)

let personDecoder = PersonDecoder()

// Prints: "The data couldn’t be read because it isn’t in the correct format."
// and `person` is nil.
let person = personDecoder.person(decodedFrom: personData)