일부 작업이 항상 실행이 완료되거나 올바른 출력을 보장하지 않습니다. 따라서 특정 상황에서 에러가 발생할 경우 Swift에서는 이를 처리할 수 있는 방법을 제시합니다.
에러 표현과 던지기
Swift의 열거형을 통해 에러 조건의 그룹을 모델링하여 에러 특성에 대한 추가 정보를 전달할 수 있습니다.
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
에러가 발생하면 구문을 정상적인 흐름으로 실행하기 어렵습니다. 따라서 throw 구문을 활용하여 에러를 발생하여, 어떤 지점에서 에러가 발생하였는지 파악할 수 있습니다.
throw VendingMachineError.insufficientFunds(coinsNeeded: 10)
에러 처리 방식
Swift에서는 에러를 처리하는 방식은 4가지 입니다.
- 해당 함수를 호출하는 코드로 에러를 전파 (throwing)
- do-catch 구문 사용
- optional 값으로 처리
- optional 값으로 에러가 발생하지 않을 것이라고 주장
에러 전파
throws로 표기된 함수(던지기 함수)를 통해 에러를 호출하여 전파합니다. 던지기 함수는 에러를 전파할 수만 있으며 던지기 선언이 되지 않은 함수 내에서 발생한 모든 에러는 함수 내에서 처리가 되어야 합니다.
# 에러 정의
enum MathError: Error {
case divisionByZero
}
# 함수 divide 정의
func divide(_ numerator: Int, by denominator: Int) throws -> Int {
if denominator == 0 {
throw MatchError.divisionByZero
}
return numerator / denominator
}
위 함수에서는 denominator 가 0일 경우, divisionByZero라는 에러를 호출하도록 함수를 정의하였습니다.
VendingMachineError 에서 열거된 에러 예시로 아래 내용을 살펴봅니다.
struct Item {
var price: Int
var count: Int
}
class VendingMachine {
var inventory = [
"candy bar" : Item(price: 12, count: 7)
"chips" : Item(price: 10, count: 4)
"pretzels" : Item(price: 7, count: 11)
]
var coinsDeposited = 0
func vend(itemNamed name: String) throws {
guard let item = inventory[name] else {
throw VendingMachineError.invalidSelection
}
guard item.count > 0 else {
throw VendingMachineError.outOfStock
}
guard item.price <= coinsDeposited else {
throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
}
coinDeposited -= item.price
var newItem = item
newItem.count -= 1
inventory[name] = newItem
print("Dispensing \(name)")
}
}
- VendingMachine이라는 클래스를 구현하여 inventory라는 arrry 형태의 instance를 만들었습니다. 해당 array에는 candy bar, chips, pretzels가 들어있습니다.
- coinsDeposited라는 매개변수를 생성하였습니다.
- vend(itemNamed: )라는 메서드를 구현하였습니다.
- item이 inventory array 내 포함된 name과 다를 시에, invalidSelection이라는 에러를 호출합니다.
- item의 수가 0이거나 0보다 작을 때, outOfStock이라는 에러를 호출합니다.
- item의 가격이 coinsDeposited 보다 클 때, insufficientFunds(coinsNeeded: item의 가격 - coinsDeposited)라는 에러를 호출합니다.
- coinsDeposited에서 item의 price 값을 뺍니다.
- item을 newItem이라는 매개변수로 만들고, newItem의 갯수를 하나 제외합니다.
- inventory 내 name을 newItem에 할당합니다.
- Dispensing \(name) 이라는 값을 출력합니다.
Do-Catch를 사용하여 에러 처리
MatchError 예시를 Do - Catch를 활용하여 처리해봅시다.
do {
let result = try divide(10, by: 0)
print("Result: \(result)")
} catch MathError.divisionByZero {
print("Error: Cannot divide by zero!")
} catch {
print("An unknown error occurred: \(error)")
}
- divisionByZero에러가 뜨면 "Error: Cannot divide by zero!"를 출력합니다.
- 그 외 다른 에러가 뜨면 "An unknown error occurred: \(error)"를 출력합니다.
에러를 옵셔널 값으로 변환
에러를 옵셔널 값으로 변환하기 위해서는 try? 를 사용합니다. try? 표현식을 평가하는 동안 에러가 발생하면 이 표현식의 값은 nil입니다.
let result1 = try? divide(10, by: 2) // 정상 작동: optional(5)
let result2 = try? divide(10, by: 0) // 오류 발생: nil
에러 전파 비활성화
표현식 전에 에러 전파를 비활성화 하기 위해서는 try! 를 작성할 수 있고, 이는 에러를 발생하지 않는다고 호출하는 것을 의미합니다.
try!를 사용하는 적절한 경우는 아래와 같습니다.
- 외부 파일이나 리소스를 로드할 때 오류 가능성이 없다고 보장되는 경우 (앱에서 반드시 포함된 리소스를 로드하는 경우)
- 테스트 환경에서 확인된 코드
- 샌드박스 환경에서만 실행되고, 오류 발생 시 프로그램 종료가 문제가 되지 않는 경우
'App Development > Swift' 카테고리의 다른 글
Swift의 고차함수 (0) | 2025.01.02 |
---|---|
Swift에서 동기와 비동기의 차이 (0) | 2024.11.30 |
Swift의 매개변수(parameter) 정리하기 (0) | 2024.11.30 |
Swift에서의 completion (0) | 2024.11.26 |
Swift의 Closure 란? (0) | 2024.11.25 |