본문 바로가기
Swift Study

Error Handling

by 창브로 2024. 2. 23.
728x90

오늘은 Swift의 에러처리(Error Handling)에 대해 알아보겠습니다!!

 

에러에는 두 가지 종류가 있습니다.

1. 컴파일 오류: 컴파일러가 코드가 잘못되었음을 알려줍니다(문법적 오류)

2. 런타임 오류: 다양한 이유로 앱이 실행하는 동안 발생합니다(앱 사망)

 

저희는 에러처리를 통해 런타임 오류를 해결하려고 합니다.

컴파일 오류는 실행 전 코드를 수정하면 되기 때문이죠.

 

근데 이게 왜 필요할까요?

 

예시를 들어보겠습니다. 대부분의 앱은 서버랑 통신을 합니다. 앱에서 정보를 서버에 요청하고, 서버는 데이터를 보내주는 상황이 많습니다.

하지만 실제 앱에서 데이터를 받아오지 못한다면 어떻게 될까요?

 

데이터를 요청하는 함수가 제대로 실행되어도 네트워크 상황이나 서버 이슈 등 수많은 이유로 데이터를 받아올 수 없을 수도 있습니다.

이러면 에러가 발생하는데 앱이 꺼지게 됩니다.

 

그래서 이러한 에러가 나더라도 앱이 꺼지지 않게 미리 에러를 처리해야합니다.

앱이 바로 꺼지는 것보단 사용자에게 이러한 에러로 문제점을 알려주고 해결할 수 있는 게 더 좋겠죠??

 

에러 처리를 하기 위해선 먼저 에러 타입 정의를 해야 합니다!

 

Error 프로토콜을 채택하면 정의한 에러 타입 열거형이, 스위프트의 에러 프로토콜 내에 통합됩니다.

enum AppError: Error {
	case largeNumber(over: Int)
    	case negativeNumber
}

 

자 이제 저희는 Custom Error를 생성했습니다.

그럼 Error를 사용해야겠죠?

이때 사용할 수 있는 키워드가 throw와 throws입니다.

throw와 throws는 각각 사용하는 법이 다릅니다. throw부터 알아보죠!

 

throw가 뭐예요?

enum AppError: Error {
	case largeNumber(over: Int)
    	case negativeNumber
}

throw AppError.largeNumber(over:100)

 

throw의 사용법은 throw 뒤에 Error 프로토콜을 채택한 타입의 인스턴스를 적어주면 됩니다.

간단하죠??

100이 넘는 숫자가 발생했다는 것을 알려주는 Error를 던져주는 것입니다.

 

throws는 뭐죠?

throw와 너무 비슷한 throws는 어떻게 사용할까요??

throw는 에러를 던질 때 사용하고 throws는 메서드, 생성자, 클로저가 내부에서 Error를 throw 할 수 있을 때 사용하는 키워드입니다!

 

 

func checkError(num: Int) throws {

	guard num > 100 else {
    	throw AppError.largeNumber(over:100)
    }
    
    print("100이하의 숫자가 들어왔습니다.")

}

 

함수를 선언할 때 throws를 붙이는 게 보이나요?

저 throws를 붙여주지 않으면 함수 내에서 throw 키워드를 사용하였을 때 오류가 납니다.

 

func checkError(num: Int) throws {

	guard num > 100 else {
    	throw AppError.largeNumber(over:100)
    }
    
    guard num > 0 else {
    	throw AppError.negativeNumber
    }
    
    print("100이하의 숫자가 들어왔습니다.")

}

 

더 나아가 이런 식으로 100보다 작고 0보다 큰 경우에만 에러가 발생하지 않고

100보다 크거나 0보다 작으면 상황에 맞는 에러를 던져주는 함수를 만들 수 있습니다.

 

함수, 메서드, 생성자, 클로제에서 throws를 선언할 때에는 파라미터 뒤에 선언해 주면 됩니다!

 

함수를 호출해 보겠습니다.

checkError(num: 10)

 

이렇게 함수를 호출하면 에러가 납니다!

throws 키워드가 추가된 함수나 메서드를 호출할 때에는 try 키워드를 사용해서 호출해야 합니다.

또 try를 사용하면 do-catch도 사용하게 됩니다.

 

try랑 do-catch가 뭐예요??

try키워드는 말 그대로 이 함수가 오류가 날 수도 있는데 그냥 시도해보겠다는 뜻입니다.

기본적으로 try 키워드는 do-catch와 같이 사용되는데요 예제를 보겠습니다.

 

enum BurgerOrderError: Error {
     case invalidSelection
     case LackOfMoney
     case outOfStock
}

struct Hamburger {
    var name: String
    var price: Int
    var count: Int
}

// 현재 내 잔액설정
let myMoney = 4000

func OrderMenu(orderedMeun: Hamburger) throws {
    if orderedMeun.name != "BigMac" {
        throw BurgerOrderError.invalidSelection
    }
    if orderedMeun.price > myMoney {
        throw BurgerOrderError.LackOfMoney
    }
    if orderedMeun.count == 0 {
        throw BurgerOrderError.outOfStock
    }
}

 

 

햄버거 주문 에러에 관한 에러 타입을 만들고 햄버거의 구조체를 만들고 에러를 발생시키는 함수를 정의하였습니다.

이제 OrderMenu를 사용해야겠죠??

 

let beafBurger = Hamburger(name: "beafBurger", price: 4600, count: 3)

do {
    try OrderMenu(orderedMeun: beafBurger)
} catch BurgerOrderError.invalidSelection {
    print("메뉴이름을 다시 확인해주세요.")
} catch BurgerOrderError.LackOfMoney {
    print("잔액이 부족합니다.")
} catch BurgerOrderError.outOfStock {
    print("현재 재고가 없습니다.")
}

 

위 예시처럼 do문 내에서 try 키워드를 통해 던진 오류를 받고 catch문 내에서는 던진 오류를 어떻게 처리를 할 것인지 정의를 합니다.

보통 여러 가지의 에러를 구체적으로 분리해 줄 때 사용합니다.

 

결과는 어떻게 나올까요?

 

 

600원이 부족하기 때문이죠 🙅🏻‍♂️

 

do-catch문을 쓰지 않고 try문을 사용할 수 있는 방법도 있습니다.

try? 와 try!인데요 주로 에러를 통합해서 관리할 때 사용합니다.

 

 

이런 식으로 오류가 나면 nil을 반환합니다. 오류가 나지 않으면 함수의 반환값을 리턴 하지만

옵셔널 값으로 나오기 때문에 옵셔널을 벗겨주고 사용해야 합니다!!

 

하지만 try! 는 오류가 나면 앱이 꺼지기 때문에 되도록이면 사용하지 않는 걸 추천드립니다!

정말 오류가 나지 않는 게 확실할 때만 사용하도록 해요🌞

 

수고하셨습니다🙇🏻‍♂️

'Swift Study' 카테고리의 다른 글

MVC  (0) 2024.02.24
Optional  (0) 2024.02.21
weak, unowned  (0) 2024.02.20
Strong Reference Cycle  (0) 2024.02.20
ARC  (0) 2024.02.20