[Swift] 예외처리 (throws, do-catch, try) 하기

EmilY
7 min readAug 29, 2019

--

안녕하세요 에밀리입니다.

오늘은 오류처리, 예외처리에 대해 알아보겠습니다.

오류 처리에는 다음 세 가지 과정이 필요합니다

  1. 오류의 종류 정의하기
  2. 발생한 오류 던지기
  3. 던진 오류 처리하기

1. 오류의 종류 정의하기 (선택사항)

먼저 오류의 종류를 정의해줍니다.

enum 오류종류이름 : Error {
case 종류1
case 종류2
.
.
.
}

오류 종류는 enum으로 정의해줍니다

예를들면 이렇게요

enum TestError : Error {     case outOfRange                      // 1     case invalidInput(testNum : Int)     // 2}

1번은 기본적인 enum 케이스이고

2번은 parameter를 받는 케이스입니다

예외상황이 많아질수록 케이스가 늘어날 수 있습니다.

그런데 1번 제목 옆에 ‘선택사항'이라고 써놨죠?

그 이유는 굳이 케이스별로 오류처리하지 않을 때도 있기 때문입니다.

그냥 간단하게 에러 출력하실거면 건너뛰도 됩니다.

그럼 이제 오류 던지는 방법으로 넘어가서 알아볼게요!

2. 발생한 오류 던지기

오류는 throws 를 이용해 던집니다.

던진다는 말이 애매할 수 있는데요.

오류를 던진다 = 오류를 처리해주는 곳으로 전달해준다 

고 생각하면 되겠습니다.

오류 처리하는 건 아래 3번에서 다룰 예정이니

지금은 오류를 어떻게 던지는지에 집중해보겠습니다.

func printNumber(_ number: Int) -> Int {    var text = ""

guard number > 0 else { return } // *
return text}

자, 위에 printNumber()라는 메소드가 있습니다.

그런데 중간 별표시된 부분에서 guard문을 썼습니다.

오류가 발생할 수도 있다는 얘기죠.

그럼 오류를 던져야겠죠?

throw 써줘야겠죠?

throw는 총 두 군데에 써줍니다.

func printNumber(_ number: Int) throws -> Int {    // 1   var text = ""

guard number > 0 else {
throw TestError.outOfRange // 2 } return text}
  1. 첫번째 throws는 오류가 발생할 가능성이 있는 메소드 제목 옆에 써줍니다.
  2. 두번째 throw ( ‘s’ 없음)은 오류가 발생할 구간에서 써줍니다.

그런데 위에 변수를 받는 케이스도 써줬죠?

enum TestError : Error {   case outOfRange                      // 1   case invalidInput(testNum : Int)     // 2}

여기서 2번이요.

이럴 경우엔 다음처럼 하면 됩니다.

func printNumber(_ number: Int) throws -> Int {       var text = ""

guard number > 0 else {
throw TestError.invalidInput(testNum: number) } return text}

꼭 number가 아니어도 넘겨주고 싶은 값을 넘겨주면 됩니다.

3. 던진 오류 처리하기

오류 처리는 trydo-catch로 합니다.

다시 printNumber 함수로 돌아가볼게요

func printNumber(_ number: Int) throws -> Int {       var text = ""

guard number > 0 else {
throw TestError.outOfRange } return text}

해당 경우, throw로 예외를 던져줬습니다.

예외를 받는 곳은 그럼 어디냐.

printNumber() 메소드를 사용하는 곳입니다.

예를들어,

class Object {    func printNumber(_ number: Int) throws -> Int {

.......
}
}

printNumber() 메소드가 클래스 Object 안에 있었다고 가정해볼게요.

우선 Object 인스턴스를 만들어주고

let object = Object()

printNumber() 메소드를 호출해줍니다.

let resultNumber = object.printNumber(-20) 

어라, 근데 printNumber에 변수로 -20이라는 음수값을 넣어줬습니다.

위의 호출로 오류가 발생하겠죠?

이때 오류가 발생하는 메소드는 try를 써줘야합니다.

따라서 위의 방식이 아니라

let resultNumber = try object.printNumber(-20)  

이렇게 try를 넣어줍니다! 오류 발생하는 메소드 앞에 말이죠.

func printNumber(_ number: Int) throws -> Int {

위에서 printNumber 뒤에 throws를 써줬다는건

이 함수에서 오류를 던진다는 의미였죠?

try의 의미는 이렇습니다.

‘이 함수가 오류가 발생할 수도 있는데, 한번 시도해볼게요.’

말 그대로 ‘시도해보겠다'는 선언이죠.

하지만 여기서 끝이 아니라 do-catch로 감싸줘야 처리를 할 수 있습니다.

do {   let resultNumber = try object.printNumber(-20)} catch {

print(error)
}

위의 do-catch 문은 오류를 처리하는 가장 간단한 방법입니다.

1번에서 오류 종류 정의하는 건 선택사항이라고 했죠?

오류를 정의하지 않아도 기본적으로 이렇게 에러를 출력할 수 있습니다.

심지어는 catch를 생략해도 무방합니다.

do {   let resultNumber = try object.printNumber(-20)} 

이렇게요

하지만 모처럼 오류 케이스를 나누어줬으니,

활용방법을 알아봅시다.

do {   let resultNumber = try object.printNumber(-20)} catch TestError.outOfRange {   // 오류처리 } catch TestError.invalidInput(let testNumber) {   // 오류처리 }

위에서 정의한 케이스별로 처리해줍니다

오류처리까지 채우면 이렇습니다

do {  let resultNumber = try object.printNumber(-20)} catch TestError.outOfRange {   print("양수가 아니야!")} catch TestError.invalidInput(let testNumber) {   print("부적절한 숫자 \(testNumber)")}

케이스별로 처리하기 때문에 switch문으로도 쓸 수 있습니다

do {   let resultNumber = try object.printNumber(-20)} catch {   switch error {
case TestError.outOfRange:
// 오류처리
case TestError.invalidInput(let number):
// 오류처리
} }

추가 설명 : try?와 try!

try는 try?나 try!로 쓸 수 있습니다.

try?

let resultNumber = try? object.printNumber(20)
print("\(resultNumber)") // Optional("20") 또는 nil

printNumber에서 오류가 발생할 수도 있다는 걸 인정하는 겁니다.

Swift에서 물음표는 옵셔널을 의미하죠.

따라서 resultNumber가 리턴값을 옵셔널 타입 또는 nil로 받을 수 있게 됩니다.

try!

let resultNumber = try! object.printNumber(-20)
print("\(resultNumber)") // "20"

printNumber 메소드에서 오류가 절!대! 발생하지 않을 자신이 있으면 씁니다.

오류발생 시 Runtime Error가 발생하고 강제종료됩니다.

이상입니다.

참조 사이트

--

--

EmilY
EmilY

Written by EmilY

iOS 하나부터 열까지 이해하기

Responses (1)