RunTime Error을 핸들링하는 방법을 공부한다.
Error Type
- 보통 열거형으로 선언
- Error 프로토콜을 채용하면 된다.
- 일반적인 타입과 달리 스위프트의 에러 처리 시스템에 통합된다.
enum DataParsingError: Error {
}
throw
- throw
expression
같이 사용된다.
- 이
expression
에는 반드시 에러타입이 와야 한다.
- 코드 블럭에서 에러를 던질 수 있어야 사용 가능하다.
throw
는 에러를 던지는 키워드고, throws
는 함수, 메소드, 생성자, 클로저 등 블록이 에러를 던질 수 있다 선언하는 키워드로 다르다.
func name(parameters) throws -> ReturnType {
statements
}
init(parameters) throws {
statements
}
{ (parameters) throws -> ReturnType in
statements
}
throwing function
import UIKit
enum DataParsingError: Error {
case invalidType
case invalidField
case missingRequiredField(String)
}
func parsing(data: [String: Any]) throws {
guard let _ = data["name"] else {
throw DataParsingError.missingRequiredField("name")
}
guard let _ = data["age"] as? Int else{
throw DataParsingError.invalidType
}
}
- return과 달리
throws
키워드가 있다고 해서 항상 에러를 던져야 하는 것은 아니다.
try Expression
throws
함수를 호출할 때 try
표현식을 사용해야 한다.
- 세 가지 형태가 있다.
try expression
try? expression
try! expression
throws
키워드가 있는 메소드는 반드시 try
키워드를 사용해야 한다.
예시
func parsing(data: [String: Any]) throws {
guard let _ = data["name"] else {
throw DataParsingError.missingRequiredField("name")
}
guard let _ = data["age"] as? Int else{
throw DataParsingError.invalidType
}
}
try? parsing(data: [:])
에러 처리 방법
do-catch
- 에러의 종류를 확인하고 개별적으로 처리하고 싶을 때 사용
do
블럭: 필수 블럭으로, 에러가 발생할 수 있는 코드를 여기서 호출
- 실행 중 에러 발생 시 do 블럭 즉시 종료
- 이어지는
catch
블럭 실행
- 특정 에러와 매칭 시켜 처리하거나, 모든 에러 처리 가능
- where 절을 추가하여 매칭시킬 에러 패턴에 조건 추가 가능
문법
do {
try expression
statements
} catch pattern {
statements
} catch pattern where condition {
statements
}
예시
func test(){
do{
try parsing(data: [:])
} catch DataParsingError.invalidType {
print("handle invalidType Error")
} catch {
print("handle error")
}
}
- 하나의 캐치 문에서 여러 에러 타입을 핸들링하는것도 가능하다.
- 캐치 블록 작성 시 까다로운 패턴부터 위에 작성해야 한다.
- if-else if처럼 위에서부터 순서대로 조건 판단
캐치문 패턴이 전부 없는 경우
- 범용 캐치문이 없다면 컴파일 에러가 발생한다.
- 혹은 해당 do-catch문이 있는 함수에서 에러를 다시 던져도 된다.
func test() throws {
do{
try parsing(data: [:])
} catch DataParsingError.invalidType, DataParsingError.invalidField {
print("handle invalidType Error")
}
}
- 이렇게 되면 작성한 패턴을 제외한 에러는 test 메소드를 호출한 코드로 전달된다.
- 이 경우 do-catch 생략 가능(test메소드를 호출한 코드에서 에러 핸들링)
패턴이 없는 캐치문만 있는 경우
- 무슨 에러가 발생했는지 구분할 수 있도록
error
라는 특별한 로컬 상수를 사용할 수 있다.
- 특정 에러 타입이 아니므로 타입캐스팅이 필요하다.
func test() throws {
do{
try parsing(data: [:])
} catch {
print("handle erro")
if let error = error as? DataParsingError {
switch error {
case .invalidType:
print("invalid Type")
default:
print("handle error")
}
}
}
}
try & Optional Binding
try? expression
try! expression
- 에러의 종류와 관계없이 성공과 실패만 구분해서 처리하고 싶을 때 사용
if let _ = try? parsing(data: [:]) {
print("success")
} else {
print("fail")
}
- 반드시 옵셔널 바인딩을 해야하는 것은 아니며, 함수 호출 후 결과를 신경쓰지 않아도 된다면 그냥 옵셔널 트라이만 작성해도 된다.
try? parsing(data: [:])