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").
Это должно быть достаточно ясно для целей отладки.