Error(에러)
에러의 종류
- 컴파일 오류: 컴파일러가 코드가 잘못되었음을 알려준다(문법적 오류/에러)
- 런타임 오류 : 다양한 이유로 앱이 실행하는 동안 발생한다 ==> 앱이 꺼진다.
에러처리가 필요한 이유
런타임에러는 프로그램이 실행하는 동안 발생하며, 크래시(앱 강제 종료)가 발생한다.
서버와 통신하는 앱등을 만들 때 정보를 서버에 요청하고, 서버는 데이터를 보내준다.
실제 앱에서 데이터를 받아오지 못한다면 어떻게될까?
데이터를 요청하는 함수가 제대로 실행이 되었다면? 함수의 결과로 데이터를 가져올 것이다.
하지만 데이터를 제대로 가져오지 못해서 에러가 발생하면 ? 앱이 꺼질 수 있다.
그 이유론 수많은 이유가 있을 수 있다. 네트워킹오류, 서버다운이슈 등.. 수 많은 경우의 수가 있다.
그래서 앱이 꺼지지 않도록 미리 에러를 처리해야 한다. 발생 가능한 에러를 미리 처리해두면 강제종료는 되지 않을 수 있다.
과연 앱이 그냥 꺼지는게 좋을까? 아니면 사용자에게 문제가 발생했다고 알리고, 다시 실행하라고 알리는게 좋을까.
후자가 사용자에겐 더 친절한 경우일 것이다.
에러는 일반적으로 함수의 처리과정에서 발생한다. 에러가 발생할 수 있는 함수는 함수를 정의할 때 예외적인 일이 발생할수 있는 함수로 정의해야한다. 이를 위해 함수를 다르게 정의하고 처리해야한다.
에러를 던질 수 있는 함수
func readData(data: Int) throws -> Bool{ //throws키워드 ==> 에러를 던질 수 있는 함수 타입이다.
if data < 0{
throw 에러
}else{
return true
}
}
throws키워드가 붙으면 함수 실행 중간에 에러를 던질 수 있는 함수가 된다. 리턴값이 Bool로 정의되어 있지만 중간에 에러를 함수 밖으로 던질 수 있다. 던진다는 의미는 "에러를 return한다"는 말과 비슷하다.
위 함수는 data가 0보다 작으면 에러를 리턴하고, 아니면 true를 리턴하는함수이다.
여기서 throw는 에러를 던지는 실제 코드이고 우린 이제 에러를 던져야한다(한글로대충써논거임..)
에러를 던지려면 던질 에러가 있어야한다. 그러면 던질 에러를 정의해야하지 않을까?
에러의 정의
enum Errors: Error{
case aError
case bError
case cError
}
에러는 열거형으로 정의하며 Error프로토콜을 채택해야한다. 왜냐하면 에러프로토콜에 정의되어있는 기능을 사용해야 하기 때문!
이렇게 에러를 정의하면 Swift가 미리 정의해놓은 Error시스템에 통합이 되어버린다.(Error프로토콜을 채택한 순간)
이중에 하나를 던진다.
func readData(data: Int) throws -> Bool{
if data < 0{
throw Errors.aError
}else{
return true
}
}
조건에 따라 다른 에러를 던질 수 있다.
에러처리의 과정
에러처리의 과정은 3단계로 이루어진다.
1단계: 에러를 먼저 정의한다
2단계: 에러를 발생할 수 있는 함수를 정의한다.
3단계: 에러를 발생할 수 있는 함수에 대한 처리를 해야한다.
에러를 발생할 수 있는 함수에 대한 처리
1. try
에러가 발생할 수 있는 함수는 함수 앞에 try라는 키워드를 붙혀서 실행해야한다.
또한 try라는 키워드가 붙은 함수는 do블럭 내에서 실행되어야 한다. do블럭은 에러가 발생하지 않았을 경우, 에러가 throw되지 않았을 경우에 실행된다.
do블럭은 catch블럭과 함께한다.
catch블럭은 do블럭에서 실행한 함수가 에러를 던졌을때 실행된다. do블럭에서 던진 에러를 catch블럭이 받아준다고 하면 된다.
do{
let result = try readData(data: -1)
//에러가 발생하지 않으면 이하 실행
print("통과")
} catch {//에러가 발생하면 이하 실행
print("에러발생 error: \(error)")
}
do{
let result = try readData(data: -1)
print("통과")
} catch let error {
print("에러발생 error: \(error)")
}
2. try?
옵셔널 트라이 방법이다.
1. 정상인경우: 옵셔널리턴타입으로 리턴
2. 에러가 발생하면 nil리턴
let Checked = try? checkHeight(height: 200) // Bool?
//옵셔널이기 떄문에 바인딩해서 사용
if let result = Checked{
}
guard let result = Checked else { return }
3. try!
Forced try방법이다.
1. 정상적인경우: 정상리턴타입으로 리턴
2. 에러가 발생하면 런타임에러
let Checked = try! checkHeight(height: 200) // Bool
Chatch블럭 처리 방법
catch블럭은 do블럭에서 발생한 에러만을 처리해야만 하는 블럭이며 모든 에러를 반드시 처리해야한다.
글로벌 스코프에서는 모든 에러를 처리하지 않아도 컴파일 에러가 발생하지 않는다.
패턴이 있는 경우 Error를 따로 받음.
do {
let Checked = try checkHeight(height: 100)
print("정상작동")
} catch Errors.bError where (조건) { // where절을 추가해서, 매칭시킬 에러패턴에 조건을 추가할 수 있음
print("키가 커서 놀이기구 타는 것 불가능")
} catch Errors.aError {
print("aError발생")
}
모든 에러를 받음.
do {
let Checked = try checkHeight(height: 100)
print("정상작동")
}catch { //error 상수 제공 error상수 활용 가능
print(error)
if let error = error as? Errors{ //실제로 정의한 구체적인 에러타입으로 다운캐스팅
switch error{
case .aError:
print("aError발생")
case .bError:
print("bError발생")
}
에러를 던지는 함수를 처리하는 함수
에러 정의
enum Errors: Error {
case aError
}
에러를 던지는 함수(무조건 에러를 던짐)
func throwingFunc() throws {
throw Errors.aError
}
에러의 처리
do {
try throwingFunc()
} catch {
print(error)
}
일반적인 함수 처리
func handlingError() {
do {
try throwingFunc()
} catch {
print(error)
}
}
//일반적인 함수로 내부에서 처리
throwing함수로 에러 다시 던지기
함수 내에서 에러를 직접 처리하지 못하는 경우, 에러를 다시 던질 수 있다.
함수 내에서 직접 처리하지 못하는 경우 에러를 다시 더질수도 있다.
func handleError1() throws {
//do {
try throwingFunc()
//}
}
do {
try handleError1() // 에러를 받아서 처리 가능
} catch {
print(error)
}
catch블럭이 없어도 에러를 밖으로 던질 수 있다. 함수 밖으로 던지게된다.
이런 경우에는 do블럭도 없어도 된다.
rethrows키워드
에러를 던지는 throwing함수를 파라미터로 받은경우, 내부에서 에러를 다시던지기가 가능하다.
함수를 파라미터로 직접적으로 사용할 때에는 에러를 다시던지기위해 rethrows키워드를 반드시 사용해야한다.
func someFunction1(callback: () throws -> Void) rethrows {
try callback() // 에러를 다시 던짐(직접 던지지 못함)
// throw (X)
}
someFunction1함수의 경우 파라미터로 에러를 던질수 있고 입력과 출력이 void인 함수를 받는다.
에러를 변환해서 다시던지는 함수
// 다시 에러를 던지는 함수(방법2) - 에러변환
func someFunction2(callback: () throws -> Void) rethrows {
enum ChangedError: Error {
case cError
}
do {
try callback()
} catch { // catch구문에서는 throw (O)
throw ChangedError.cError // 에러를 변환해서 다시 던짐
}
}