코드를 아무리 신중하게 설계하고 구현했다 해도 앱을 통제할 수 없는 상황은 언제든지 발생할 수 있다.
앱이 할 수 있는 것은 이러한 에러를 확실하게 처리할 수 있도록 구현하는 것이다.
에러도 타입을 통해 선언할 수 있으며 열거형으로 되어 있다.
예를 들어, 원격 서버에 파일을 전송하는 메서드가 있다고 가정한다면, 이 메서드는 여러 원인으로 인하여 파일 전송에 실패할 가능성이 있다.
이 외에도 많은 경우가 있을 것이다. 이러한 모든 에러를 Error 프로토콜을 따르는 열거형 내에서 표현되도록 할 수 있다.
아래와 같이 에러 타입을 선언하면 에러가 발생할 때 사용할 수 있다.
// Error 프로토콜을 따르는 나만의 에러 타입 (열거형)
enum FileTransferError: Error {
// 에러가 갖게 될 상황들을 값으로 정의함
case noConnection
case lowBandwidth
case fileNotFound
case TooBigSize
}
위에서는 에러 타입 선언을 통해 에러가 갖게 될 수 있는 상황을 값으로 정의했다. 이번엔 throw / guard 구문을 통해 에러가 발생할 수 있는 상황을 만들어볼 것이다.
guard 라는 키워드가 사용되었다고 해서 어려워 하지 말고, if문과의 반대 개념이라고 생각하면 쉽다.
즉 false일 때 내부 코드가 성립한다.
// 임의로 상황을 만들어보는 예제 코드
let connectionOK: Bool = true
let connectionSpeed: Double = 50.00
let fileFound: Bool = true
let fileSize: Int = 30
// 이 함수는 실행중에 오류가 발생할 수 있다. -> throws 키워드
func transferFile() throws {
// connectionOK가 false이면 else 구문 실행 -> true이면 그냥 pass
guard connectionOK else {
throw FileTransferError.noConnection
}
guard connectionSpeed > 30 else {
throw FileTransferError.lowBandwidth
}
guard fileFound else {
throw FileTransferError.fileNotFound
}
guard fileSize < 20 else {
throw FileTransferError.TooBigSize
}
}
하지만 이렇게 발생할 수 있는 에러 상황을 생각하여 코드를 작성했음에도 미처 발견하지 못한 에러가 발생할 수 있다.
do-catch 구문을 사용하며 transferFile 메서드를 호출하여, 해당 에러에 대한 설명을 담고 있는 문자열 값을 반환한다.
또한 가장 마지막 catch 절은 에러에 대한 패턴 매칭이 이뤄지지 않은 상태에 대한 것으로, 앞선 catch 구문과 일치하지 않는 모든 에러를 처리할 수 있도록 해준다.
// let connectionOK: Bool = true
// let connectionSpeed: Double = 50.00
// let fileFound: Bool = true
// let fileSize: Int = 30
* 만약 connectionOK false 라면 다음 catch 구문을 통해 No Network Connction 이라는 문자열이 반환된다.
// 파일 전송을 "시도" 하고 결과를 문자열로 반환하는 함수
func sendFile() -> String {
// do catch 했을때 어떤 에러가 오더라도 처리할 수 있도록
do {
try transferFile()
} catch FileTransferError.noConnection {
return "No Network Connction"
} catch FileTransferError.lowBandwidth {
return "File Transfer Speed too low"
} catch FileTransferError.fileNotFound {
return "File Not Found"
// 에러 상황을 일부러 만들어서 그 상황을 확인할 수 있다.
// 즉 놓친 에러를 직접 출력한다.
} catch let error {
print("error: \(error)")
return "Unknown Error"
}
// 성공적으로 전송이 완료되었습니다.
return "Successful transfer"
}