동기 비동기에 많이 나오는 에러 핸들링!
처음 봤을 때 멘붕 왔던 에러 핸들링..!
말이 너무 비슷비슷해서 헷갈리는 에러 핸들링에 대한 정리를 블로그에도 올려봅니다..
에러 핸들링은 말 그대로 에러를 다루는 거겠죠?
Error Handling
에러 핸들링(처리)의 순서가 있어요! 제가 보기에는..
- 내가 만든 함수에서(?) 발생할 수 있는 에러 형식 선언 (enum을 통해서 정의)
- 에러 정의(선언한 에러가 어떤 경우에 발생하는 에러인지 정의)
- 에러 발생시 어떻게 할 것인지 정의
그러면 정말로.. 이게 뭔데? 싶으니까 에러를 던지고 받고를 해봅시다.
그럼 어떻게 던지는데? 넹.. throw(s)를 통해서 던집니다.
Error Throw(s)
- throw : 에러를 던지는 키워드(에러가 발생했을 때만 호출됨!!)
- throws : 함수 메서드 생성자 클로저가 에러를 던질 수 있다고 선언하는 것
- throws 표현식을 호출할 때는 try 표현식을 사용함!
그럼 이제 위에서 말한 걸 보고 직접,, 차례대로 해봅시다.
enum을 통해서 에러 프로토콜을 선언한 에러를 직접 정의해요.
enum DataParsingError: Error {
case invalidType
case invalidField
case missingRequiredField(String)
}
throws, throw 구분하여 에러 핸들링를 해봅시다.
지금 파싱 함수가 에러를 던질 수 있는 함수라는 것을 선언한 것이고,
guard문 을 통해서 ___가 없다면 throw를 통해서 "어떤"에러라는 것을 던져주고 있습니다!
func parsing(data: [String: Any]) throws { // 데이터 딕셔너리로 선언
// data에 name이란 키가 없을 때 선언한 에러 케이스 리턴
guard let _ = data["name"] else {
throw DataParsingError.missingRequiredField("name")
}
// 데이터의 age의 value 데이터가 INT로 타입 캐스팅이 불가할 경우 에러 케이스 리턴
guard let _ = data["age"] as? Int else {
throw DataParsingError.invalidType
}
}
다시 말하면,, 지금 parsing이라는 함수가 에러를 던질 수 있음을 throws를 통해서 나타내고
그래서 진짜 에러가 발생했다면 throw를 통해서 어떤 에러인지 키워드를 던져주는 것이에요.
근데 에러 하면 try 라는 것도 꼭 같이 나오거든요?
얘는 함수말고 표현식이 에러를 뱉는지 안 뱉는지에 대한 것입니다..
그럼 이 try 는 무엇인지 확인해보죵...
Try 표현식 톺아보기
- try은 표현식이 에러를 발생할 수 있다면 사용해야하는 키워드임!! (얘도 종류 있음)
- try? : 에러 발생시 nil return
- try! : 에러 발생시 런타임에러 (비사용 추천)
- do - catch 실행문!
- do : 필수 구현문, 에러가 발생할 수 있는 표현식은 try로 호출함
- try문에서 에러가 발생하면 catch문이 실행됨
- 에러 조건에 where으로 조건 추가 가능
- 정리하자면, 에러를 발생할 수 있는 표현식은 try로 감싸주어야 함. 근데 그런 try를 사용하기 위해서는 do - catch 실행문을 통해서 실행할 수 있음!
- do 안에서 try로 에러를 발생할 수 있는 표현식을 실행하고, 만약에 에러가 발생했다면 catch문에서 어떤 에러인지 확인 하는 느낌!
간단한 사용 예시)
func handleError() {
do {
try parsing(data: [:])
} catch DataParsingError.invalidField {
print("invalidField 에러 발생")
} catch DataParsingError.invalidType {
print("invalidType 에러 발생")
} catch { // 나머지 구현하지 않은 에러인 missingRequiredField 에러와 매칭됨
print("handle error")
}
}
- 이렇게 패턴이 생략된 에러 catch는 항상 마지막에 넣어주어야함
- 에러 핸들링은 작은것 → 큰것 순으로 catch 해주어야함
만약 패턴이 생략된 에러 catch문을 사용하지 않는다면,
함수가 나머지 에러들은 다른 코드로 던지도록 선언해야 함
func handleError() throws {
do {
try parsing(data: [:])
} catch DataParsingError.invalidType {
print("invalidType 에러 발생")
}
}
나머지 에러는 handleError를 호출한 곳으로 전달됨 (에러의 결과를 다른곳으로 보내버리는 것)
패턴이 없는 캐치블럭만으로 핸들링하기
- 발생한 에러 error라는 특별한 상수를 사용할 수 있음 → 선언한 에러 형식으로 타입 캐스팅하여 사용하면됨
func handleError() throws {
do {
try parsing(data: [:])
} catch {
if let error = error as? DataPrasingError {
switch error {
case .invalidField:
print("invalidField error")
case .invalidType:
print("invalidType error")
default:
print("error 발생")
}
}
}
}
간단~하게 에러 핸들링에 대해서 정리해봤습니다..
수업시간에 한것과 같이 정리했으면 더 보시기 쉬웠을 것 같은데
그건 좀 더 다듬어서 앱스쿨에 정리해 놓을게요.
혹시 틀린게 있다면 댓글 .. 부탁드립니다!!!
그럼 오포완!!
'Swift > Swift 기초문법' 카테고리의 다른 글
DispatchQueue(GCD)를 알아보자2, GCD 사용시 주의해야할 사항 (0) | 2023.11.08 |
---|---|
DispatchQueue(GCD)를 알아보자, 이제 동기/비동기, 동시/직렬을 곁들인.. (2) | 2023.11.03 |
[Swift 기초문법] @State, @Binding 을 알아보자 (0) | 2023.07.10 |
[Swift 기초문법] Generics을 알아보자 (0) | 2023.07.10 |
[Swift 기초문법] Property를 알아보자 (0) | 2023.06.16 |