안녕하세요 에밀리입니다.
오늘은 오류처리, 예외처리에 대해 알아보겠습니다.
오류 처리에는 다음 세 가지 과정이 필요합니다
- 오류의 종류 정의하기
- 발생한 오류 던지기
- 던진 오류 처리하기
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}
- 첫번째 throws는 오류가 발생할 가능성이 있는 메소드 제목 옆에 써줍니다.
- 두번째 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. 던진 오류 처리하기
오류 처리는 try와 do-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가 발생하고 강제종료됩니다.
이상입니다.