Swift에서는 런타임 에러가 발생한 경우에 처리를 위한 일급 클래스를 제공합니다.
처리를 위해 발생, 감지, 증식, 조작을 지원합니다.
Error라는 프로토콜을 준수하는 타입의 값을 통해 표현되는데,
이 프로토콜은 사실상 요구사항이 없는 빈 프로토콜 입니다.
그래도 오류를 표현하기 위한 타입 (예를들면 열거형)은 이 프로토콜을 채택합니다.
다른언어의 exception처리와 비슷하지만, 다른점은 call stack과 unwinding과 관련이 없어
비교적 많은 계산이 필요하지 않다는 점입니다. 그래서 에러를 반환하는
throw구문은 일반적인 반환 구문인 return 구문과 비슷한 성능을 보여줍니다.
표현
enum KindfError: Error{
case error1
case error2
case error3
//...
}
게임내에서 상점을 이용할 경우를 간략하게 만들어보겠습니다.
enum ShopError: Error{
case invalidInput
case insufficientFunds(_ moreNeeded: Int)
case outOfStack
}
계속 작성해보겠습니다.
class Shop{
var itemPrice = 100
var itemCount = 5
var deposited = 0
func receiveMoney(_ money: Int) throws {
// 입력한 돈이 0이하면 오류를 던집니다
guard money > 0 else {
throw ShopError.invalidInput
}
// 오류가 없으면 정상처리를 합니다
self.deposited += money
print("\(money)원 받음")
}
// 물건 팔기 메서드
func vend(numberOfItems numberOfItemsToVend: Int) throws -> String {
// 잘못된 아이템 갯수를 입력했을 때
guard numberOfItemsToVend > 0 else {
throw ShopError.invalidInput
}
// 구매하려는 총 금액보다 소유한 금액이 적을 때
guard numberOfItemsToVend * itemPrice <= deposited else {
let moneyNeeded: Int
moneyNeeded = numberOfItemsToVend * itemPrice - deposited
throw ShopError.insufficientFunds(moneyNeeded)
}
// 구매하려는 수량이 실제 수량보다 많을 때
guard itemCount >= numberOfItemsToVend else {
throw ShopError.outOfStock
}
// 오류검사 후, 오류가 없다면 정상적으로 시행
let totalPrice = numberOfItemsToVend * itemPrice
self.deposited -= totalPrice
self.itemCount -= numberOfItemsToVend
return "\(numberOfItemsToVend)개 판매했습니다."
}
}
// Shop의 인스턴스 생성
let machine: Shop = Shop()
// 판매 결과를 반환받을 변수
var result: String?
직접 예제를 작성하다보니 이것저것 붙이다보니깐.... 너무 일을 벌리는거같아서
다음에 코테나 프로젝트 작성시 사용해보는걸로 하고 예제를 그대로 사용했습니다.
오류 처리
오류를 처리하기 위한 코드도 작성해야 합니다.
do-catch
모든 오류케이스에 대응하는 가장 정석적인 방법입니다.
do {
try shop.receiveMoney(0)
} catch ShopError.invalidInput{
print("유효하지 않은 입력입니다.")
} catch ShopError.insufficientFunds(let moreNeeded) {
print("\(moneyNeeded)원이 부족합니다")
} catch ShopError.outOfStock {
print("수량이 부족합니다")
}
// 유효하지 않은 입력입니다
switch 구문을 사용해서 한 catch블럭으로 처리하는 방법
do {
try machine.receiveMoney(300)
} catch /*(let error)*/ {
switch error {
case ShopError.invalidInput:
print("입력이 잘못되었습니다")
case ShopError.insufficientFunds(let moneyNeeded):
print("\(moneyNeeded)원이 부족합니다")
case ShopError.outOfStock:
print("수량이 부족합니다")
default:
print("알수없는 오류 \(error)")
}
} // 300원 받음
모든 오류를 한번에 처리하는 방법
딱히 모든 에러케이스에 반응할 필요가 없는경우 이렇게 사용할수도 있습니다.
do {
result = try shop.selling(numberOfItems: 4)
} catch {
print(error)
} // insufficientFunds(100)s
do {
result = try shop.selling(numberOfItems: 4)
}
try
try?
오류발생시 nil을 결과값으로 받고 오류처리의 결과를 통보받지 않습니다.
정상동작 했다면 옵셔널 타입으로 반환값을 받습니다.
result = try? shop.selling(numberOfItems: 2)
result // Optional("2개 판매했습니다.")
result = try? machine.vend(numberOfItems: 2)
result // nil
* 위에서 물품 5개중 4개를 구매해서 1개가 남은 상태입니다.
try!
정상동작 후에 바로 결과값을 돌려받습니다.
대신, 오류발생시 런타임 오류가 발생하며 애플리케이션은 정지합니다!
result = try! shop.selling(numberOfItems: 1)
result // 1개 판매했습니다.
//result = try! shop.selling(numberOfItems: 1)
// 런타임 오류발생, 애플리케이션 정지
공부에 도움을 준 사이트
전반적인 공부 가이드라인
yagom.net/courses/swift-basic/lessons/%ec%98%a4%eb%a5%98%ec%b2%98%eb%a6%ac/
스위프트 공식 가이드 번역 사이트
jusung.gitbook.io/the-swift-language-guide/language-guide/17-error-handling
'Language > Swift' 카테고리의 다른 글
Swift 접근제어 (0) | 2021.03.16 |
---|---|
Swift 고차함수 (0) | 2021.03.15 |
Swift 익스텐션 (Extensions) (0) | 2021.03.15 |
Swift 프로토콜 기초 (0) | 2021.03.14 |
Swift Assert와 Guard (0) | 2021.03.14 |