Swift 기초문법

Swift: try-catch

zoonee 2022. 3. 19. 18:07

 

 

try - catch 에러처리란?

 

  • 프로그램 내에서 에러가 발생한 상황에 대해 대응하고 이를 복구하는 과정
  • swift에서는 런타임에 에러가 발생한 경우 이를 처리하기 위해서 1급 클래스를 제공한다
    • 발생(throwing)
    • 감지(catching)
    • 전파(propagating)
    • 조작(manipulating)

 

→ swift에서 에러는 에러프로토콜을 따르는 타입의 값으로 표현된다. 에러프로토콜은 요구사항이 없는 빈 프로토콜이지만 오류를 표현하기 위해서는 이 프로토콜을 채택해야 한다. swift열거형은 오류원인을 나누고 해당오류에 특성에 대한 추가정보를 전달하는 모델을 만드는데 적합하다. 그러면 PhoneError라고 네이밍을 하고, Error프로토콜을 채택을 하였다. Error종류로 case unknown을 만들어주고 case batteryLow를 만들어주고, batteryLow에는 연관값을 넣어주면 batteryLevel 그리고, Int값으로 연관값을 선언해주었다. 이렇게 열거형을 통해 오류의 종류를 표현하는 것이 가장 일반적인 방법이다. 오류가 발생하면 정상적인실행을 계속 할 수 없다는 것을 나타내는데 만약 배터리가 부족할 때 에러를 발생시키려면 thorw라는 구문을 사용하면 오류를 발생시킬 수 있다. throw구문을 이용해 오류를 발생시켜보자. throw를 적어주고 PhoneError.battery가 부족하면 에러를 발생시켜야 하니 batteryLow를 적어주고, 현재 배터리가 얼마 남았는지 알려주기 위해 연관값 batteryLevel에 20%가 남았다 가정하고 20을 적어준다. 실행해보면 위 사진처럼 에러가 발생된다. 

 

오류를 던질수도 있지만 오류가 던져진것에 대비하여 던져진 오류를 처리하기 위한 코드도 작성해야 한다. 예를들어 던져진 오류가 무엇인지 판단하여 다른 방법으로 문제해결을 시도한다던지 사용자에게 오류를 알리는등의 코드를 작성해야 한다.

 

Swift에서 오류를 처리하는 4가지 방법이 있다.

 

  1. 함수에서 발생한 오류를 해당함수를 호출한 코드에 전파하는 방법
  2. 두캐치 구문을 이용해서 오류를 처리하는 방법
  3. 옵셔널값으로 오류를 처리하는 방법
  4. 오류가 발생하지 않을것이라고 확신하는 방법

 

첫번째 방법을 확인해보자. 오류가 발생할 수 있음을 나타내기 위해서는 함수, 매개변수, 생성자매개변수 뒤에 throws라는 키워드를 작성해주면 된다. 그러면 핸드폰의 배터리상태를 체크하는 함수를 하나 만들어보자. 

 

func를 선언하고 checkPhoneBatteryStatus라는 함수 이름을 지어주었다. 그리고 매개변수로 배터리잔량을 뜻하는 batteryLevel을 적어주고, Int형이 값이 전달되게 작성해주었다. 그리고 매개변수 뒤에 throws라는 키워드를 작성해주면 된다. throws로 표시된 함수는 throwing함수라 하고 만약에 함수에 반환값이 있다면 throws 키워드 뒤에 반환값을 작성하면 된다. 그럼 String이 반환되게 해보자. throwing함수는 함수 내부에서 throw되는 오류를 함수가 호출된 곳으로 전파하는데 throwing함수만 에러를 전파할 수 있다. 

 

그러면 checkPhoneBatteryStatus라는 throwing함수에 오류를 던지는 코드를 작성해보자. guard문으로 함수매개변수로 전달받은 batteryLevel이 -1이면 else구문에서 unknown에러를 던져본다. guard문은 false일때 else구문이 실행되고 함수가 조기종료된다. 그래서 guard문에 batteryLevel에 -1이 아니면 이라는 조건을 적었다. 만약에 -1이면 조건이 false가 될테니 else구문이 실행되고, unknown에러를 던진 후 함수가 실행된다. 그리고 guard문으로 batteryLevel이 20보다 작거나 같으면 throw로 batteryLow 에러를 던져주는데 battery가 20%남았다고 알려주기 위해 연관값을 20을 적어주었다. 위의 guard조건이 다 걸리지 않으면 반환값으로 "배터리 상태가 정상입니다."라고 문자열이 반환되어 출력된다.

 

이렇게 checkPhoneBatteryStatus함수에는 guard문과 throw문을 사용하여 오류를 처리하고, guard문의 코드가 오류를 발생하면 else로 넘어가서 throw문에 의해 폰에러오류를 발생시키고 메소드를 종료시킨다. 즉 2개의 가드문에서 모두의 오류가 발생하지 않아야 정상적으로 다음코드가 수행될 수 있다. 이 메소드를 사용하려면 오류를 발생할 수도 있기 때문에 두 catchtry? try!를 사용해서 오류를 처리할 수 있어야 한다. 먼저 do catch문을 사용해서 오류를 처리하는 방법을 알아보자.

 

→ 함수 메소드생성자 등에서 오류를 던져주면 오류발생을 전달받은 코드블록은 두 캐치구문을 사용해서 오류를 처리해주면 되는데 do절 내부 코드에서 오류를 던지고 catch절에서 오류를 전달받아 예외처리 해주면 된다. 두 캐치구문은 보통 다음과 같이 표현한다. 두 코드블럭안에 트라이키워드를 적고 오류가 발생가능한 코드를 적어주면 되고, catch옆에 오류패턴을 적어주고 블록안에는 오류상황에 맞는 적절한 예외처리를 작성해주면 된다. do catch 구문이 어떻게 사용되는지 알아보자.

 

 

do try 오류가 발생할수도 있는 checkPhoneBatteryStatus 함수를 호출하고 batteryLevel 매개변수값에는 -1을 넘겨주었다. 그리고 catch PhoneError가 unknown이면 print로 "알 수 없는 에러입니다."가 출력되게 해주고 catch PhoneError가 batteryLow이면 연관값을 상수로 전달받게 해주고 그리고 print를 이용해서 "배터리 전원 부족 남은 배터리 : \(연관값) %" 이 출력되게 하였다. 마지막으로 catch만 적어주고 unknow에러도 batteryLow 에러도 아니라면 이 캐치블록이 실행될텐데 catch뒤에 오류의 종류를 명시하지 않아도 코드블록을 생성하면 블록내부에 암시적으로 error라는 지역상수가 오류내용으로 들어오게 된다. 만약 이 catch블록이 실행된다면 어떤 에러인지 알 수 있게 print함수로 "그 외 오류 발생: \(에러라는 이름의 지역상수)"가 출력되게 해주었다. 이렇게 작성하면 checkPhoneBatteryStatus 함수가 오류를 발생시켜도 catch문이 오류를 잡아 개발자가 오류상황에 맞는 적절한 예외처리를 할 수 있다. 실행해보면 "알 수 없는 에러입니다."가 출력되는걸 확인 할 수 있다.

 

함수를 호출할 때 배터리레벨의 매개변수에 -1을 전달했으니 함수내부에서 unknown Error를 던질거고, catch구문에서 던져진 에러가 unknown이니까 print로 알 수 없는 에러입니다. 가 출력되게 된다. 만일 배터리레벨 매개변수에 20을 전달하면 

"배터리 전원 부족 남은 배터리 : 20%" 라는 문자열이 출력되는걸 확인 할 수 있다. 20이라는 값은 연관값으로 전달받은 값이다.

 

 

→ 이제 에러를 처리하는 두번째 방법인 try? 를 사용하면 오류를 옵셔널값으로 변환하여 처리할 수도 있다. try?를 표현을 통해 동작하던 코드가 오류를 던지면 그 코드의 반환값은 nil이 된다. 코드와 같이 에러가 발생하는 checkPhoneBatteryStatus 함수를 호출할 때 함수 이름앞에 try? 를 붙여주고 status상수를 출력해보면 nil이 반환되는걸 확인할 수 있다. checkPhoneBatteryStatus함수가 unknown이라는 에러를 던져주기 때문에 status상수가 nil이 된다. 

 

 

→ 만약 함수가 에러를 던져주지 않는다면 옵셔널값이 출력되는걸 확인 할 수 있다.

 

 

→ 마지막으로 try! 로도 에러를 처리할 수 있는데 try? 와 마찬가지로 코드와 같이 에러가 발생하는 것 같은 함수 이름에 try! 키워드를 붙여주면 된다. try! 는 throwing함수나 메소드가 에러를 던져주지 않을것임을 확실할 때 사용하는 방법이다. 코드를 개발하는 개발자가 오류를 던지는 함수또는 메소드를 호출할 때 오류가 절대로 발생하지 않을것이라고 확신할 수 있는 상황이라면 try! 를 사용할 수 있다. 만약 throwing함수나 메소드가 오류를 던진다면 런타임 에러가 발생하여 프로그램이 강제로 종료되기 때문에 주의하면서 사용해야 한다. 그러면 위 코드를 실행해보면 에러가 발생되지 않으니 배터리상태가 정상입니다. 라고 출력이 된다. 만약에 에러를 발생시킨다면 프로그램이 강제로 종료된다.

'Swift 기초문법' 카테고리의 다른 글

Swift: 고차함수(map, filter, reduce)  (0) 2022.03.19
Swift: 클로저(Closure)  (0) 2022.03.19
Swift: 옵셔널체이닝  (0) 2022.03.19
Swift: 열거형(enum, case, rawValue)  (0) 2022.03.19
Swift: 익스텐션(extension)  (0) 2022.03.19