Swift Catch Pattern, который связывает ошибку с переменной

Использование Swift 4.2 и XCode 10

В Swift 4.2 DecodingError является перечислением. Есть (в настоящее время) четыре разных случая. Я могу отследить каждый случай отдельно и связать переменные, которые можно использовать для регистрации ошибки, как показано в следующем коде...

do {
    let model = try jsonDecoder.decode(BattleShip.self, from: jsonData!)
    print(model)
} catch DecodingError.dataCorrupted(let context) {
    print(context.debugDescription)
} catch DecodingError.keyNotFound(let key, let context) {
    print("\(key.stringValue) was not found, \(context.debugDescription)")
} catch DecodingError.typeMismatch(let type, let context) {
    print("\(type) was expected, \(context.debugDescription)")
} catch DecodingError.valueNotFound(let type, let context) {
    print("no value was found for \(type), \(context.debugDescription)")
} catch {
    print("I know not this error")
}

Но это много кода, чтобы поместить везде, где я мог столкнуться с ошибкой декодирования. И, если мой блок do{} имеет несколько вызовов, которые выдают, мне, возможно, придется обрабатывать ошибки, которые эти методы вызывают по-разному. Шаблон, который я пытаюсь реализовать, выглядит следующим образом... где decodingError (error) содержит весь грязный код выше

do {
    let object1 = try decoder.decode(SomeClass.self, from: someData)
    try object2.methodThatThrowsSomeOtherError()
} catch <all decoding errors> {      // this is invalid pseudocode
    MyCentralLogger.log.decodingError(error)
} catch let nonDecodingError {
    MyCentralLogger.log.error(nonDecodingError)
}

У меня может быть шаблон перехвата, подобный этому, который, кажется, удовлетворяет всем случаям перечисления (по крайней мере, он компилируется)

} catch is DecodingError {

но компилятор не может автоматически связать переменную error, и я не вижу ни одной опции

} catch let decodingError is DecodingError {  // THIS IS NOT VALID

Если я просто перехватываю все ошибки, я легко могу иметь переключатель в центральном методе, который соответствующим образом разделяет различные случаи ошибок декодирования. Но я хочу быть в состоянии избежать отправки ошибок не декодирования в этот коммутатор. Я также могу отделить свои блоки do{}, чтобы выполнять в нем только этапы декодирования, но это также делает код беспорядочным, особенно если вы декодируете несколько сообщений, перемежающихся с другими действиями.

Предложения? Спасибо всем!

3 ответа

Решение

Синтаксис, используемый в catch строка точно такой же синтаксис шаблона, который используется в case из switch, Если вы знаете, как написать case ты умеешь писать catch,

Так, например, вы жалуетесь:

} catch let decodingError is DecodingError {  // THIS IS NOT VALID

Правильно. Но это действительно так:

} catch let decodingError as DecodingError { 

О, какая разница в одном письме.

Это все еще намного больше кода, чем хотелось бы, но, возможно, немного чище:

      } catch DecodingError.keyNotFound(_, let context),
        DecodingError.valueNotFound(_, let context),
        DecodingError.typeMismatch(_, let context),
        DecodingError.dataCorrupted(let context) {
    print(context.debugDescription)
    MyCentralLogger.log.decodingError(context.underlyingError)
} catch {
    print(error.localizedDescription)
    MyCentralLogger.log.error(error)
}

Сочетая как действительные ответы, так и switchзаявление, следующее сэкономит вам несколько почти идентичных строк:

      do {
    let model = try jsonDecoder.decode(BattleShip.self, from: jsonData!)
    print(model)
} catch let decodingError as DecodingError {
    switch decodingError {
    case .typeMismatch(_, let c), .valueNotFound(_, let c), .keyNotFound(_, let c), .dataCorrupted(let c):
        print(c.debugDescription)
    }
} catch {
    print(error.debugDescription)
}

Если, например, ваши декодированные данные не соответствуют свойству index: Int, он будет печатать

Нет значения, связанного с ключом CodingKeys(stringValue: "index", intValue: nil) ("index").

Это должно быть достаточно ясно для целей отладки.

Другие вопросы по тегам