** edwith - Swift 프로그래밍 입문 강의 참고 **
# 오류 발생 #
- 스위프트에서 오류는 Error라는 프로토콜을 준수하는 타입의 값을 통해 표현됩니다.
- Error 프로토콜은 사실 상 요구사항이 없는 빈 프로토콜일 뿐이지만, 오류를 표현하기 위한 타입(주로 열거형)은 이 프로토콜을 채택합니다.
[ 오류 표현 ]
- Error 프로토콜과 (주로) 열거형을 통해서 오류를 표현
/* 자판기 동작 오류의 종류를 표현한 VendingMachineError 열거형 */
enum VendingMachineError: Error {
case invalidInput
case insufficientFunds(moneyNeeded: Int)
case outOfStock
}
[ 함수에서 발생한 오류 던지기(throw) ]
class VendingMachine {
let itemPrice: Int = 100 // 상품 가격
var itemCount: Int = 5 // 상품 개수
var deposited: Int = 0 // 들어온 돈 총액
/* 돈 받는 메서드 */
func receiveMoney(_ money: Int) throws {
// 입력한 돈이 0 이하면 오류 발생 //
guard money > 0 else {
throw VendingMachineError.invalidInput
}
// 오류가 없으면 정상 처리 //
self.deposited += money
print("\(money)원 받음")
}
/* 물건 파는 메서드 */
func vend(numberOfItems numberOfItemsToVend: Int) throws -> String {
// 원하는 아이템의 수량이 0 이하로 잘못 입력되었으면 오류 발생 //
guard numberofItemsToVend > 0 else {
throw VendingMachineError.invalidInput
}
// 요구되는 가격보다 미리 넣어둔 돈이 적으면 오류 발생 //
guard numberOfItemsToVend*itemPrice <= deposited else {
let moneyNeeded: Int
moneyNeeded = numberOfItemsToVend * itemPrice - deposited
throw VendingMachineError.insufficientFunds(moneyNeeded: moneyNeeded)
}
// 자판기 수량보다 요구하는 수량이 많으면 오류 발생 //
guard itemCount >= numberOfItemsToVend else {
throw VendingMachineError.outOfStock
}
// 오류가 없으면 정상처리 //
let totalPrice = numberOfItemsToVend * itemPrice
self.deposited -= totalPrice
self.itemCount -= numberOfItemsToVend
return "\(numberOfItemsToVend)개 제공"
}
}
/* 자판기 인스턴스 */
let machine: VendingMachine = VendingMachine()
/* 판매 결과를 전달받을 변수 */
var result: String?
# 오류 처리 #
- 오류발생의 여지가 있는 throws 메서드는 try를 사용하여 호출
[ do - catch ]
- 오류 발생 여지가 있는 throws 메서드는 do-catch 구문 활용
do {
try machine.receiveMoney(0)
} catch VendingMahineError.invalidInput {
print("입력이 잘못되었습니다")
} catch VendingMahineError.insufficientFunds(let moneyNeeded) {
print("\(moneyNeeded)원이 부족합니다")
} catch VendingMahineError.outOfStock {
print("수량이 부족합니다")
}
/* 출력
"입력이 잘못되었습니다"
*/
[ do - catch 에서 switch 사용 ]
- 위와 다를 바 없음
do {
try machine.receiveMoney(300)
} catch {
switch error {
case VendingMachineError.invalidInput:
print("입력이 잘못되었습니다")
case VendingMachineError.insufficientFunds(let moneyNeeded):
print("\(moneyNeeded)원이 부족합니다")
case VendingMachineError.outOfStock:
print("수량이 부족합니다")
default:
print("알수없는 오류 \(error)")
}
}
/* 출력
"300원 받음"
*/
- 딱히 케이스 별로 오류 처리할 필요 없으면 catch 구문 간략화/생략 가능
do {
result = try machine.vend(numberOfItems: 4)
} catch {
print(error)
}
/* 출력
insufficientFunds(100)
*/
do {
result = try machine.vend(numberOfItems: 4)
} // catch 생략
[ try? ]
- 별도의 오류처리 결과를 통보받지 않고 오류가 발생했으면 결과값을 nil로 돌려받을 수 있습니다.
- 정상동작 후, 옵셔널 타입으로 정상 반환값을 돌려 받아요.
result = try? machine.vend(numberOfItems: 2)
result // Optional("2개 제공함")
result = try? machine.vend(numberOfItems: 2)
result // nil
[ try! ]
- 오류가 발생하지 않을 것이라는 강력한 확신을 전달해주어, 정상동작 후에 바로 결과값을 돌려받아요.
- 오류가 발생하면 런타임 오류 -> 애플리케이션 동작 중지
result = try! machine.vend(numberOfItems: 1)
result // 1개 제공함
result = try! machine.vend(numberOfItems: 1) // 런타임 오류 발생!!!!!
# 그 외 오류 처리 (rethrows, defer) #
[ rethrows ]
- 최소 하나 이상의 오류 발생 가능한 함수를 매개변수로 전달 받아야 사용 가능
- 부모클래스의 rethrows메서드를 자식클래스의 throws메서드로 오버라이드 불가능
- 부모클래스의 throws메서드를 자식클래스의 rethrows메서드로 오버라이드 가능
- 프로토콜의 throw요구 함수를 rethrows를 사용하여 부합시키지 못합니다.
- 프로토콜의 rethrows요구 함수를 throw를 사용하여 부합시킬 수 있습니다.
func authenticateuser(method: () throws -> Bool) rethrows {
try method()
print("Success!")
}
[ defer ]
- 현재 코드 블록을 나가기 전에 꼭 실행되어야 하는 코드가 실행되도록 보장해줍니다.
- 함수, 메서드, 반복문, 조건문 등등 코드 블록 어디에서든 사용 가능
- defer 구문 내부에서는 break, return 등과 같은 빠져나가는 코드 작성 X
- 여러 개의 defer 구문이 하나의 블록 내부에 속해 있다면, 맨 마지막에 작성된 구문부터 역순으로 수행됩니다.
func printStringNumbers() {
defer { print("1") }
defer { print("2") }
defer { print("3") }
print("4")
}
/* 출력
4321
*/
'iOS > Swift' 카테고리의 다른 글
Swift-11. 고차 함수 - map, filter, reduce (0) | 2023.02.24 |
---|---|
Swift-9. 프로토콜(protocol), 익스텐션(extension) (0) | 2023.02.24 |
Swift-8. assert, precondition, guard (0) | 2023.02.24 |
Swift-6. 옵셔널 체이닝, nil 병합 (0) | 2023.02.24 |
Swift-5. 인스턴스 생성 및 소멸 (0) | 2023.02.24 |
댓글