enum HeightError: Error { //에러 프로토콜 채택 (약속)
case maxHeight
case minHeight
}
func checkingHeight(height: Int) throws -> Bool { // (에러를 던잘수 있는 함수 타입이다)
if height > 190 {
throw HeightError.maxHeight
} else if height < 130 {
throw HeightError.minHeight
} else {
if height >= 160 {
return true
} else {
return false
}
}
}
do {
let isChecked = try checkingHeight(height: 200)
print("놀이기구 타는 것 가능: \(isChecked)")
} catch {
print("놀이기구 타는 것 불가능")
}
do {
let isChecked = try checkingHeight(height: 200)
if isChecked {
print("청룡열차 가능")
} else {
print("후룸라이드 가능")
}
} catch {
print("놀이기구 타는 것 불가능")
}
let isChecked = try? checkingHeight(height: 200)
//당연히, 옵셔널 타입을 벗겨서 사용해야함
try! (Forced 트라이) —> 에러가 날 수 없는 경우에만 사용 가능
let isChecked2: Bool = try! checkingHeight(height: 150)
// 에러가 발생할 수 없다고 확신이 있는 경우만 사용해야 함
do {
let isChecked = try checkingHeight(height: 100)
print("놀이기구 타는 것 가능: \(isChecked)")
} catch HeightError.maxHeight { // where절을 추가해서, 매칭시킬 에러패턴에 조건을 추가할 수 있음
print("키가 커서 놀이기구 타는 것 불가능")
} catch HeightError.minHeight { // 생략가능
print("키가 작아서 놀이기구 타는 것 불가능")
}
do {
let isChecked = try checkingHeight(height: 100)
print("놀이기구 타는 것 가능: \(isChecked)")
} catch { // error 상수를 제공 (모든 에러가 넘어옴)
print(error.localizedDescription)
if let error = error as? HeightError { // 실제 우리가 정의한 구체적인 에러 타입이 아니고, 에러 타입(프로토콜)이 넘어올 뿐
switch error {
case .maxHeight:
print("키가 커서 놀이기구 타는 것 불가능")
case .minHeight:
print("키가 작아서 놀이기구 타는 것 불가능")
}
}
}
// 스위프트 5.3 버전 업데이트
do {
let isChecked = try checkingHeight(height: 100)
print("놀이기구 타는 것 가능: \(isChecked)")
} catch HeightError.maxHeight, HeightError.minHeight { // 케이스 나열도 가능해짐
print("놀이기구 타는 것 불가능")
}
func handleError() {
do {
try throwingFunc()
} catch {
print(error)
}
}
handleError()
func handleError1() throws {
//do {
try throwingFunc()
//} // catch블럭이 없어도 에러를 밖으로 던질 수 있음 ⭐️
}
do {
try handleError1() // 에러를 받아서 처리 가능
} catch {
print(error)
}
// 다시 에러를 던지는 함수(방법1)
func someFunction1(callback: () throws -> Void) rethrows {
try callback() // 에러를 다시 던짐(직접 던지지 못함)
// throw (X)
}
// 다시 에러를 던지는 함수(방법2) - 에러변환
func someFunction2(callback: () throws -> Void) rethrows {
enum ChangedError: Error {
case cError
}
do {
try callback()
} catch { // catch구문에서는 throw (O)
throw ChangedError.cError // 에러를 변환해서 다시 던짐
}
}
// 실제 에러를 다시던지는(rethrowing)함수를 처리하는 부분
do {
try someFunction1(callback: throwingFunc)
} catch {
print(error)
}
do {
try someFunction2(callback: throwingFunc)
} catch {
print(error)
}
// 에러 정의
enum NameError: Error {
case noName
}
// 생성자와 메서드에도 적용 가능
class Course {
var name: String
init(name: String) throws {
if name == "" {
throw NameError.noName
} else {
self.name = name
print("수업을 올바르게 생성")
}
}
}
// 에러 처리 (생성자에 대한)
do {
let _ = try Course(name: "스위프트5")
} catch NameError.noName {
print("이름이 없어 수업이 생성 실패하였습니다.")
}
class NewCourse: Course {
override init(name: String) throws {
try super.init(name: name)
}
}
할일을 미루는 defer문에 대한 이해
func deferStatement1() {
defer {
print("나중에 실행하기")
}
print("먼저 실행하기")
}
deferStatement1()
func deferStatement2() {
if true {
print("먼저 실행하기")
return
}
defer { // 디퍼문이 호출되어야, 해당 디퍼문의 실행이 예약되는 개념
print("나중에 실행하기")
}
}
deferStatement2()
// 등록한 역순으로 실행 ====> 일반적으로 하나의 디퍼문만 사용하는 것이 좋음
func deferStatement3() {
defer {
print(1)
}
defer {
print(2)
}
defer {
print(3)
}
}
deferStatement3()
// 어떻게 실행될까?
for i in 1...3 {
defer { print ("Defer된 숫자?: \(i)") }
print ("for문의 숫자: \(i)")
}