에러는 컴파일 에러와 런타임 에러로 구분할 수 있다. 컴파일 에러는 우리가 코드를 치는 동안 발생하는 문법적 오류들을 XCode에서 알려주는 것들을 말한다. 런타임 에러는 실제 프로그램 실행중에 오류로 인해 앱이 꺼지는 오류를 말한다. 런타임 에러는 사용자들에게 UX 적으로 좋지 못한 경험을 주기 때문에 미리 에러 처리를 통해 런타임 에러를 막아야 한다. 런타임 오류가 발생하는 상황의 예시로는 네트워크 통신을 통해 데이터를 받아와 화면을 표시해야하는데, 데이터를 받아오지 못한 경우 발생할 수 있다.
그럼 런타임 에러가 발생할 때 프로그램이 바로 꺼지는 것이 아닌 유저에게 안내를 해주고 꺼지게 하는 방법은 없을까?
[에러 타입 정의] Error는 열거형이므로 미리 정의한 후 사용할 수 있다. 또한 Error 정의 시 Swift 내 Error 프로토콜을 채택해 사용해야한다.
[에러 함수 정의] 함수를 작성할 때 이 함수는 에러를 발생시킬 수 있는 함수라고 미리 정의할 수 있다. 아래 코드처럼 함수를 정의할 때 throws 키워드와 함께 사용 후 에러의 상황에서 throw 키워드와 해당하는 Error를 던진다.
[에러 함수 실행] 에러를 발생시킬 수 있는 함수라는 표시인 throws와 함께 선언된 함수는 일반적인 함수 실행과 달리 try 키워드를 앞에 붙인 뒤 함수를 호출해야한다. 또한, try 키워드는 do-catch문에서 사용할 수 있다. catch 문에서는 반드시 모든 에러를 처리해야하는데, catch NumError.aError {} 로 각 에러에 따른 처리를 할 수도 있고 catch {}를 통해 기본으로 공통된 에러처리를 할 수도 있다. 또한 catch NumError.aError where 추가 조건 {} 과 같은 형태로 where 절을 추가해 추가 조건 처리도 할 수 있다. catch문에는 error라는 상수를 제공해 이를 활용해 처리할 수도 있는 점 알아두자. error를 출력할 때는 error.localizedDescription을 주로 사용한다.
// Error 정의
enum NumError: Error {
case aError
case bError
case cError
}
// Error 함수 정의
func throwErrorFunc(num: Int) throws -> Bool {
if num > 10 {
return true
} else {
if num < 0 {
throw NumError.aError
}
return false
}
}
// Error 함수 실행
do {
// 에러가 발생하지 않은 정상적인 경우의 처리
try throwErrorFunc()
} catch {
// 에러가 발생한 경우의 처리
}
위 정석적인 방법 외 Error 함수를 실행하는 다른 방법도 존재한다. 아래 두 방법은 do-catch문과 함께 사용하진 않는다.
try? Optional try라고 불리는 이 방법은 옵셔널 타입으로 리턴하는 것을 말한다. 정상적인 경우 정상적인 리턴 타입을 리턴하고, 에러인 경우에는 nil을 리턴한다.
try! Force try라로 불리는 이 방법은 에러가 발생할 수 없는 경우에만 사용한다. 정상적인 경우 정상적인 리턴 타입을 리턴하고, 에러가 발생하면 런타임 에러가 발생한다.
에러를 처리하는 다른 방법들도 존재한다.
1. 함수 내에서 에러를 직접적으로 처리하지 못하는 경우에는 error를 다시 던질 수 있다
func handleError throws {
try throwingFunc()
}
do {
handleError()
} catch {
print(error)
}
2. 에러를 던지는 함수를 파라미터로 사용하는 경우, rethrowing 함수로 에러 던지기가 가능하다. 아래 코드와 같이 rethrow 키워드를 사용하면 된다.
func someFunc (callback: () throw -> Void) rethrows {
try callback()
}
do {
try someFunc(callback: throwingFunc)
} catch {
print(error)
}
3. 메서드나 생성자에서도 throwing 메서드, 생성자로 정의할 수 있다. 단, 반드시 재정의 할 때 throwing 메서드와 생성자로 재정의해야하고 일반적인 메서드나 생성자로의 재정의는 불가능하다.
추가로 defer문도 알아보자. defer문은 코드의 실행을 스코프가 종료되는 시점으로 연기시키는 문법이다. 일반적으로는 어떤 동작의 마무리 동작을 특정하기 위해 사용된다. 단, defer문은 반드시 한번은 호출이 되어야 스코프 종료 시점에 실행이 된다. 그리고 defer문은 등록한 역순으로 실행되는 특징이 있다
func deferFunc() {
defer {
print("defer")
}
print("실행")
}
'FRONT-END > iOS' 카테고리의 다른 글
iOS 화면 시스템 (프레임 vs 오토레이아웃) (0) | 2023.08.10 |
---|---|
Xcode MARK, 코드 스니펫 설정하는 법 (0) | 2023.08.10 |
Swift 델리게이트 패턴 이해하기 (0) | 2023.08.07 |
Swift 메모리 관리(ARC) (0) | 2023.08.06 |
Swift 고차함수 (map, filter, reduce) (0) | 2023.08.04 |
댓글