Swift의 온도

Swift #15 - 에러처리

IT의 온도 2021. 1. 26. 00:43

 

1. 예외 상황

 

- 예외 상황

#예외가 발생할 수 있는 상황

 *파일 처리 중 디스크 에러

 *권한이 부족한 상황

 

#에러 발생해도 크래쉬 되지 않도록

 

- 에러 발생 API

#예외가 발생할 수 있는 상황

*throws로 선언
*파일에 저장 API
 
func write(toFile: String,
    atomically useAuxiliaryFile:Bool,
    encoding enc: String.Encoding) throws
cs

 

- throws 함수 호출하기

#throws 함수 호출하기

*try를 이용해서 호출
*컴파일 에러 안 남
*그러나 에러 발생 - 애플리케이션 크래쉬
 
try str.write(toFile: filePath, atomically: true, encoding: .utf8)
cs

 

- 에러 다루기

#에러 다루기

*에러가 발생 -> 애플리케이션의 크래쉬 방지
*do-catch 블로과 함께 사용
*에러가 발생하면 catch 내 코드 실행
 
do {
    try str.write(toFile: wrongFilePath,
        atomically: true, encoding: .utf8)
}
catch {
    print("에러 발생")
}
cs

 

#발생한 에러 정보 얻기

*catch에서 에러 바인딩
 
do {
    try str.write(toFile: wrongFilePath, atomically: true,
encondig: .utf8)
}
catch let error {
    print("에러 발생", error)
}
cs

 

- 반환값과 에러

#반환값이 있는 함수의 에러

init(contentsOffile path: String)) throws{}
func increasePositive(num : Int) throws -> int {}
 
*try를 이용한 호출
 
let str = try String(contentsOfFile: filePath)
let num = try incresePositive(num: 99)
 
*에러 다루기 : do-catch
 
do {
    let str3 = try String(contentsOfFile: wrongFilePath)
}
catch let error {}
cs

 

#try? 로 호출하기

*에러 발생 시 nil 반환
*반환 타입은 옵셔널
 
let str = tryString(contentsOfFile: wrongFilePath)
cs

 

#try! 로 호출하기

*에러 발생 시 애플리케이션 크래쉬
*반환 타입은 언래핑(non-optional)
 
let str = tryString(contentsOfFile: wrongFilePath)
cs

 

2. 커스텀 에러 정의

 

- 에러 정의

#커스텀 에러 정의

 *Error 프로토콜

 *NSError 클래스(Foundation 프레임워크)

 

#Error 프로토콜로 커스텀 에러 정의

 *Enum으로 정의

 *Struct/Class로 정의

 

#Enum으로 에러 정의

*Enum의 원소 타입을 Error으로
 
enum CustomError : Error {
    case myFault
    case yourFault
}
 
*에러 발생시키기 : throw
 
throw CustomError.myFault
cs

 

#구조체와 클래스로 에러 작성

*Error 프로토콜 채택
 
struct CustomErrorStruct : Error {
    var msg : String
}
 
class CustomErrorClass : Error {
}
 
*에러 발생 시키기
 
let error = CustomErrorStruct(msg:"Oooops!")
throw error
cs

 

- 에러 다루기

#에러 구분하기

*Enum으로 정의한 개별 에러 다루기
*catch 에서 Enum에 에러 나열
*swtich-case와 비슷한 방식
 
do {
    throw CustomError.youtFault
}
catch CustomError.myFault {
    print("내탓")
}
catch CustomError.youtFault {
    print("남탓")
}
 
*struct/class로 정의한 에러
*where를 이용한 타입 체크로 구별
 
do {
    let error = CustomErrorStruct(msg:"Oooops!")
    throw error
}
catch let error where error is CustomErrorStruct {
    print("구조체로 작성한 에러 발생")
}
catch let error where error is CustomErrorClass {
    print("클래스로 작성한 에러 발생")
}
catch let error {
    print("그외 에러 발생", error)
}
cs

 

3. 에러 발생 가능 API 작성

 

- 에러가 발생할 수 있는 함수

#에러 발생 가능한 함수 작성

*0 보다 큰 수만 입력
*그 외 입력값에는 에러
 
func inputPositive(val : int) throws {
    guard val > 0 else {
        throw CustomError.yourFault
    }
    print("정상 수행")
}
 
*호출/에러 다루기
 
do {
    try inputPositive(0)
catch {
    print("에러 발생")
}
cs

 

- 반환값이 잇는 함수와 에러

#반환값이 있는 에러 발생 가능 함수

*0보다 큰 수를 입력 가능, 1증가된 값 반환
*그 외 입력에는 에러 발생
 
func inputPositive(num : int) throws -> Int {
    guard num > 0 else {
        throw CustomError.yourFault
    }
    return num + 1
}
cs

 

#반환값이 있는 에러 발생 함수 사용하기

*호출, 에러 처리, 반환값 얻기
 
do {
    let ret = try increasePositive(num: 1)
}
catch let error {
}
 
*try? 로 호출/에러 발생 - nil 반환
 
let reslut = try? dangerousFunction()
 
*try!로 호출/에러 발생 시 = 크래쉬
 
let result = try! dangerousFunction()
cs

 

 

- 내부에서 에러 다루기

#함수 내부에서 에러 다루기

*함수 내부에 에러 발생 가능 함수 호출
*do-catch로 함수 내부에서 에러 다루기
 
func dolt() {
    do {
        try dangerousFunction()
    }
    catch let error {
        print("에러를 함수 내부에서 다루기", error)
    }
}
 
*호출
 
dolt()
cs

 

- 발생한 에러를 전파하는 함수

#내부에서 발생한 에러 전파

*함수 내부에 do-catch 없음. throws 작성
 
func dolt2() throws {
    //에러를 처리하지 않고 전파한다.
    try dangerousFunction()
}
 
*호출. throws 함수이므로 try, do-catch 사용
 
do {
    try dolt2()
}
catch let error {
}
cs

 

- 에러 발생 클로저

#에러 발생 클로저를 사용하는 함수 정의

*파라미터에서
 
func dolt(_ arg : () throws -> () ) {
}
 
*반환 타입에서
 
func dolt2() -> throws -> () {
    return dangerousFunction
}
cs

 

#클로저에서만 발생한 에러 전파 : rethrow

func dolt3(_ arg : () throws -> () ) rethrow {
    try arg()
}
 
*함수 사용하기, 클로저 파라미터로 입력
 
do {
    try dolt3 {
        throw CustomError.myFault
    }
}
catch let error {
}
cs

 

4. 클린업

 

- 에러가 발생할 수 있는 함수

#클린업(defer)

*try-catch-finally 와 유사 그러나 다름
*finally는 try-catch와 함께 작성
*defer는 예외가 발생하는 곳에 작성
 
func dangerousFunction() throw {
    defer {
        print("동작 마무리")
    }
    throw CustomErrorStruct(msg: "에러 발생!")
}
cs