링크: https://www.edwith.org/boostcamp_ios/
오류를 표현하는 방법은 에러 프로토콜을 사용한다!
주로 열거형을 통해 오류를 표현한다
enum 오류이름: Error {
case 종류1
case 종류2
case 종류3
...
}
// 자판기 동작 오류의 종류를 표현한 vendingMachineError
enum VendingMachineError: Error {
case invalidInput
case insufficientFunds(moneyNeeded: Int) //열거형의 연관값
case outOfStock
}
// 오류들은 어떻게 발생시키지?
// 특정 함수안에서 이런 오류가 발생했다는걸 자신을 호출한 함수에
// 오류를 던져준다! throws를 사용해서 오류를 내포하는, 발생할수있는 함수임을 표시한다
class VendingMachine {
let itemPrice: Int = 100
var itemCount: Int = 5
var deposited: Int = 0
func receiveMoney(_ money: Int) throws {
guard money > 0 else {
throw VendingMachineError.invalidInput
}
self.deposited += money
print("\(money)원 받음")
}
func vend(numberOfItems numberOfItemsToVend: Int) throws -> String {
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?
오류발생 여지가 있는 함수를 사용할 때는 try를 사용해야한다!!!
try, try?, try! 세종류가 있다
do-catch문 활용
do {
try machine.receiveMoney(0)
} catch VendingMachineError.invalidInput {
print("입력이 잘못되었습니다")
} catch VendingMachineError.insufficientFunds(let moneyNeeded) {
print("\(moneyNeeded)원이 부족합니다")
} catch VendingMachineError.outOfStock {
print("수량이 부족합니다")
}
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)")
}
}
호출할때마다 [ do try 함수호출 catch 에러케이스 ] 에러케이스 각각에 대해 처리하기 귀찮을수있다
그럴땐 간단하게
do {
result = try machine.vend(numberOfItems: 4)
} catch {
print(error)
}
do {
result = try machine.vend(numberOfItems: 4)
}
이렇게 해도댐!
근데 이것도 깨름칙하잖아 그래서 try? try!가 있음
별도의 오류처리 결과를 통보받지 않고 오류가 발생했으면 결과값을 nil로 돌려받는거야
정상동작후엔 옵셔널 타입으로 정상 반환값을 돌려받을수있다!
result = try? machine.vend(numberOfItems: 2)
result // Optional("2개 제공함")
// 오류가 발생한다면 nil
result = try! machine.vend(numberOfItems: 1)
result // "1개 제공함" 옵셔널이 아닌 일반타입의 반환값을 돌려받을거야
전달인자로 함수를 전달받거나 함수실행의 결과를 함수로 반환하는함수를 말함
map, filter, reduce가있다
map
컨테이너 내부의 기존 데이터를 변형해서 새로운 컨테이너를 생성한다
let numbers: [Int] = [0, 1, 2, 3, 4]
numbers라는 배열의 요소를 어떤 형태로 변환하고 싶다
두배로 변환하거나 문자열로 변환하거나 하고싶다
for구문을 쓰게 되면
각각의 배열을 만들고 기존 배열을 이터레이션하여 구할수있을거야
var doubledNumbers: [Int]
var strings: [String]
doubledNumbers = [Int]()
strings = [String]()
for number in numbers {
doubledNumbers.append(number * 2)
strings.append("\(number)")
}
그런데 이렇게 하면 변수를 선언하고 반복문을 돌려야한다는 귀찮음이 발생해
doubledNumbers = numbers.map({ (number: Int) -> Int in
return number * 2
})
map의 전달인자 자리에 클로저가 들어와!
어떻게 변환해서 뭘로 돌려줄거냐 지정해줄수있어.
Int요소 하나하나 받아와서 다시 Int로 반환할거다. 새로운 컨테이너에 넣어달라
strings = numbers.map({ (number: Int) -> String in
return "\(number)"
})
// 매개변수, 반환 타입, 반환 키워드를 생략한 후행클로저를 사용하면?
doubledNumbers = numbers.map { $0 * 2 }
strings = numbers.map { "\($0)" }
이렇게 간단하게 만들수도 있다!!! 대박이네
filter
컨테이너 내부의 값을 걸러서 새로운 컨테이너로 추출
// for구문 사용시..var 사용
var filtered: [Int] = [Int]()
for number in numbers {
if number % 2 == 0 {
filtered.append(number)
}
}
// filter메소드 사용시..let 사용
let evenNumbers: [Int] = numbers.filter {
(number: Int) -> Bool in
return number % 2 == 0
}
// 매개변수, 반환타입, 반환 키워드 생략, 후행클로저
let oddNumbers: [Int] = numbers.filter {
$0 % 2 != 0
}
reduce
컨테이너 내부 콘텐츠를 하나로 통합
let someNumbers: [Int] = [2, 8. 15]
// for 구문 사용시
var result: Int = 0
for number in someNumbers {
result += number
}
// reduce 사용시
// 초기값을 지정해주고
let sum: Int = someNumbers.reduce(0, {
(first: Int, second: Int) -> Int in
return first + second
})
let sumFromThree = someNumbers.reduce(3) { $0 + $1 }