티스토리 뷰

 

INDEX

1. 에러 처리가 필요한 이유

2.  에러 처리 방법

3. 예제를 통한 에러 처리 연습

4. rethrows 키워드

5. 생성자와 메서드에서 throw 

6.  마무리

 

 

 

 

1. 에러 처리가 필요한 이유

에러의 종류는 2가지 

   1) 컴파일 에러: 스위프트 문법과 관련된 에러(컴파일러가 미리 알고 수정해야한다고 고맙게 알려줌)

   2) 런타임 에러: 프로그램이 실행되는 동안 발생

 

런타임 에러 -> 크래시(별도의 알림 없이 앱이 강제로 종료됨)

: 발생가능한 에러를 미리 처리해 두면, 강제종료되지 않음 (개발자가 처리해야만 하는 에러)

 

런타임 에러 처리가 왜 필요할까?

 - 앱이 실행하는 중간에 꺼질까?

 - 어떤 얘기치 못한 상황이 발생할 수 있음(보험 느낌으로 필요)

 - 우리가 구현한 기능이 100% 정확히 동작한다고 보장할 수 없음

 - (네트워크 통신을 하는 등의 경우에서) 서버에서 데이터를 못 받아와서 => 꺼짐

 - 앱을 사용하는데 그냥 꺼지는 게 좋은가?

  아니면 예를들어 "서버에서 문제가 발생했습니다. 잠시뒤에 다시 접속해 주세요"라고 알려주는 것이 좋은가?

    당연히 후자..

 - 프로세스 중에서, 예외적인 상황(에러)이 발생할 가능성을 미리 처리해두면

   앱이 무작정 꺼지는 것 예방가능 ⭐️

 

 - 에러는 일반적으로 동작. 즉, 함수의 처리과정에서 일어남

 - 함수를 정의할때, 예외적인 상황을 발생시킬 수 있는 함수(에러 발생 가능 함수)라고 정의하고 처리하는 과정

 

 

 

2.  에러 처리 방법: do-catch, try, try?, try!

일반적인 순서: 에러정의 - 에러 발생 가능 함수 정의 - 에러 처리

 

1. 에러 정의 

에러 프로토콜(Error)을 채택하여 어떤 에러가 발생할 경우(case)를 미리 정의함

enum HeightError: Error {   
    case maxHeight
    case minHeight
}

2. 에러가 발생 가능 함수 정의

참고로 throws키워드와 throw키워드는 다르다

throws는 함수 선언문에서 파라미터 뒤에 에러를 던지는 함수라는걸 알려주기 위해 선언하는 것이며

throw는 함수 내부에서 오류를 던지는(throw 행위 그자체)를 뜻한다.

func checkingHeight(height: Int) throws -> Bool {    // (에러를 던잘수 있는 함수 타입이다)
    
    if height > 190 {
        throw HeightError.maxHeight
    }
    else if height < 130 {
        throw HeightError.minHeight
    }
    
    else {
        if height >= 160 {
            return true
        } else {
            return false
        }
    }
}

 

위 예제는 일반적인 에러처리 코드를 나타낸 것이며, do-catch문과 try가 자주 쓰이나,

try?와 try!도 있기 때문에 아래에서 다룬다.

3. 에러 처리 방법: do-catch, try

do블럭  - 함수를 통한 정상적인 처리의 경우 실행하는 블럭

catch블럭 - 함수가 에러를 던졌을 경우 처리 실행하는 블럭

do {
    let isChecked = try checkingHeight(height: 150)
    
    print("놀이기구 타는 것 가능: \(isChecked)")
    
} catch {
    
    print("놀이기구 타는 것 불가능")
    
}

//놀이기구 타는 것 가능: false

 

try, try?, try! - 3개 모두 다르다

 

종류 특징
try - do-catch 구문과 반드시 함께 사용
- 에러 발생시 앱이 종료가 되지 않고 catch구문 실행
try? - do-catch 구문 없이 사용 가능
- 에러 발생시 nil값을 리턴
- 에러 발생 X -> (반환타입은) 옵셔널로 래핑되서 반환
try! - 에러가 발생시 크래쉬( 앱 강제 종료 )
- 반환 타입은 언래핑된 값
- 오류가 발생하지 않는다는 보장아래 사용(안전성면에서 권장되는 방법은 X)

https://boidevelop.tistory.com/40#comment13560277 

1.  try + do-catch블럭: 에러 정식 처리 방법 

// 1) 에러 정의 (어떤 에러가 발생할지 경우를 미리 정의)
enum HeightError: Error {  //에러 프로토콜 채택
    case maxHeight
    case minHeight
}



// 2) 에러가 발생할 수 있는 함수에 대한 정의
func checkingHeight(height: Int) throws -> Bool {
    
    if height > 190 {
        throw HeightError.maxHeight
    } else if height < 130 {
        throw HeightError.minHeight
    } else {
        if height >= 160 {
            return true
        } else {
            return false 
        }
    }
}

do {
    let isChecked = try checkingHeight(height: 150)
    
    if isChecked {
        print("청룡열차 가능")
    } else {
        print("후룸라이드 가능") //위에서 return false
    }
} catch {
    print("놀이기구 타는 것 불가능")
}

//후룸라이드 가능

 

2. try? - optional로 오류 처리하는 방법

에러를 던지면 nil로 반환하며

옵셔널 타입이기 때문에 정상적인 값이 있어도, 감싸져있음 => 언래핑필요

let isChecked = try? checkingHeight(height: 170)      // Bool?

//옵셔널 타입이므로, 언래핑 필요

 

3. try! - 오류가 발생하지 않을 것이라고 확신하는 방법 (권장X)

throw함수 호출시 오류가 절대 발생하지 않을것이라 확신할때 사용하며

에러가 만약 발생시 런타임 에러 발생함

let isChecked2: Bool = try! checkingHeight(height: 150)      // Bool
let isChecked2: Bool = try! checkingHeight(height: 2000)      // 런타임에러 발생

// 에러가 발생할 수 없다고 확신이 있는 경우만 사용해야 함

 

do-catch문 

do-catch문 정식 문법

do - catch문 정식 문법

do-catch문 예제

do {
    
    let isChecked = try checkingHeight(height: 100)
    print("놀이기구 타는 것 가능: \(isChecked)")
    
} catch HeightError.maxHeight  {    // 여기에 where절을 추가, 매칭시킬 에러패턴에 조건을 추가가능
    
    print("키가 커서 놀이기구 타는 것 불가능")
    
} catch HeightError.minHeight {      // 생략가능(switch의 default문느낌)
    
    print("키가 작아서 놀이기구 타는 것 불가능")
    
}

//키가 작아서 놀이기구 타는 것 불가능

 

Catch블럭의 간편한 처리 (Swift 5.3)

do {
    let isChecked = try checkingHeight(height: 100)
    print("놀이기구 타는 것 가능: \(isChecked)")
    
} catch HeightError.maxHeight, HeightError.minHeight {   // 케이스 나열도 가능해짐🍯
    print("놀이기구 타는 것 불가능")
}

//놀이기구 타는 것 불가능

 

 

3. 예제를 통한 에러 처리 연습

 

 

1. 에러정의 - 에러 발생 가능(던지는) 함수 정의 - 에러 처리

// 에러정의
enum SomeError: Error {
    case aError
}


// 에러를 던지는 함수 정의 (무조건 에러를 던진다고 가정)
func throwingFunc() throws {
    throw SomeError.aError
}


// 에러의 처리
do {
    try throwingFunc()
} catch {
    print(error)
}

 

2. 함수내부에서 do-catch문으로 자체적으로 처리하기

//func throwingFunc() throws {
//    throw SomeError.aError
//}

func handleError() {
    do {
        try throwingFunc()
    } catch {
        print(error)
    }
}

 

3.throwing함수로 에러를 다시 던지는 함수(throwing함수 자체적으로 에러처리 불가함)

=> rethrowing함수를 위해 이해할 필요가 있음

//func throwingFunc() throws {
//    throw SomeError.aError
//}

func handleError1() throws {
    //do {
    try throwingFunc()
    //}                     // do-catch블럭이 없어도 에러를 밖으로 던질 수 있음 ⭐️
}

do {
    try handleError1()   // 에러를 받아서 처리 가능
} catch {
    print(error)
}

 

 

4. rethrows 키워드

rethrows?

함수(메서드)에 rethrows키워드를 사용하여 파라미터로 전달받는 함수(콜백함수)가 에러를 던진다는 것을 나타내는 키워드

주의점❗️

1. rethrows키워드를 사용해 에러를 다시 던지기 위해서는

최소 하나 이상의 에러발생가능 함수를 파라미터로 전달받아야함(에러를 던져야 하기때문.. 당연한 말임)

2. rethrows키워드를 사용한 함수 내부에서는 에러를 직접 던지지 못함 - throw사용 불가능

// 에러정의
enum SomeError: Error {
    case aError
}

//에러던지는 함수 정의
func throwingFunc() throws {
    throw SomeError.aError
}

//다시(again!!) 에러를 던지는 rethrowing 함수!
func someFunction1(callback: () throws -> Void) rethrows {
    try callback()             // 에러를 다시 던짐(직접 던지지 못함)
    // throw (X)
}

//실제로 에러 다시던지는(rethrowing) 함수 처리하는 부분
do {
    try someFunction1(callback: throwingFunc)
} catch {
    print(error) //aError
}

위코드를 설명하면

맨 아래의someFunction1(callback: throwingFunc)를 try하는것에서 시작하여

rethrowing함수 someFunction1를 통해 throwingFunc의 에러인 SomeError의 aError를 다시 던지고(rethrows)

맨아래의 catch블럭에서 그 에러(SomeError.aError)를 catch해 출력하는 코드

 

 

3. do - catch구문 내부의 try 를 이용한 구문에서, 오류가 발생하면, 

오류를 호출하고 catch 절 내부에서 다른 오류를 던짐으로써 오류를 던지는 함수에서 발생한 오류를 제어할 수 있다.

나는 이게 처음봤을때 단번에 이해가 가지 않았다...catch문인데 오류를 다시 던진다? 하지만

이는 윗 rethrows예제를 이해했으면 충분히 이해가능하다. 먼저 코드를 보자

// 에러정의
enum SomeError: Error {
    case aError
}

//에러던지는 함수 정의
func throwingFunc() throws {
    throw SomeError.aError
}

// 다시 에러를 던지는 함수(방법2) - 에러변환
func someFunction2(callback: () throws -> Void) rethrows {
    
    //변환하기위한 에러 정의
    enum ChangedError: Error {
        case cError
    }
    
    do {
        try callback()
    } catch {   // catch구문에서는 throw (O)❗️❗️
        throw ChangedError.cError    // 에러를 변환해서 다시 던짐
    }
}

do {
    try someFunction2(callback: throwingFunc)
} catch {
    print(error) // cError
}

위의 문장처럼 코드를 설명하면

위 코드 역시 맨 아래의someFunction2(callback: throwingFunc)를 try하는것에서 시작하여

rethrowing함수 someFunction2를 통해 throwingFunc의 에러인 SomeError의 aError를 다시 던지지만(rethrows)

외부로 던지는게 아니라 바로 catch하여,

ChangedError의 cError로 바꾼뒤에, 진짜로 외부로 던져서! 

맨아래의 print문에서 cError로 에러가 변경되어 출력된 것

 

 

 

5. 생성자와 메서드에서 throw 

 

생성자와 메서드에서의 throw키워드 적용하기

에러는throwing함수 뿐만아니라, 메서드와 생성자에도 적용 가능하다.

자주 쓰이는 문법은 아니기에 간단히 정의하고 마무리한다.

에러는 던질 수 있는 메서드는 Throwing메서드

에러는 던질 수 있는 생성자는 Throwing생성자

 

// 에러 정의

enum NameError: Error {
    case noName
}

// 생성자에 적용 가능
class Course {
    var name: String
    
    init(name: String) throws {
        if name == "" {
            throw NameError.noName
        } else {
            self.name = name
            print("수업을 올바르게 생성")
        }
    }
    
}

// 에러 처리 (생성자에 대한)

do {
    let _ = try Course(name: "")
} catch NameError.noName {
    print("이름이 없어 수업이 생성 실패하였습니다.")
}

//재정의

class NewCourse: Course {
    
    override init(name: String) throws {
        try super.init(name: name)
        
    }
}

 

throwing 메서드의 재정의 규칙

 - Throwing 메서드/생성자는 재정의할 때, 반드시 Throwing메서드/생성자로 재정의해야함

   (Throwing 메서드/생성자를 일반 메서드/생성자로 재정의 불가능❗️)

 

 - 일반 메서드/생성자를 Throwing 메서드/생성자로 재정의 하는 것은 가능

   (일반 메서드/생성자의 범위가 더 큼)

 

 [상속관계에서]

상위 하위 O / X
일반 throws 재정의 O
throws throws 재정의 O
throws 일반 재정의 X
throws rethrows 재정의 O
rethrows throws 재정의 X

Throwing메서드와 Rethrowing메서드를 비교하면 Rethrowing메서드의 범위가 더 작다!

 

 

6.  마무리

 

에러를 정의하고, 에러발생가능 함수를 정의하고 에러를 처리해보는 예제를 만들어 볼 수 있고,

try, try?, try!의 차이점과 do-catch블럭이 어떠한 형태로 쓰이는지 알고,

rethrows를 통하여 에러를 다시 던질 수 있다는 개념을 익히고,

rethrows와 throws의 재정의 가능 범위를 알았다면 pass

 

 

 

반응형

'Swift' 카테고리의 다른 글

Swift [Generic]  (0) 2023.03.08
Swift [Closure 3부]  (0) 2023.03.04
Swift [Closure 2부]  (0) 2023.03.04
Swift [ARC- strong, memory leak, weak, unowned]  (0) 2023.03.02
Swift [Closure 1부]  (0) 2023.03.01
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함