[TIL] 2022-10-04 Swift 에러 핸들링

Jongdroid·2022년 10월 4일
3

TIL

목록 보기
19/24
post-thumbnail

에러 핸들링 이해하기

코드를 아무리 신중하게 설계하고 구현했다 해도 앱을 통제할 수 없는 상황은 언제든지 발생할 수 있다.

  • 활성화된 인터넷 연결을 기반으로 동작하는 앱은(채팅 앱 등)아이폰이 네트워크 신호를 잃는 것을 제어할 수 없다.
  • 사용자가 비행기 모드를 활성화하는 것 또한 막을 수 없다.

앱이 할 수 있는 것은 이러한 에러를 확실하게 처리할 수 있도록 구현하는 것이다.

  • 앱을 계속 이용하려면 활성화된 인터넷 연결이 필요하다는 것을 사용자에게 알린다.

Swift에서 에러를 처리하는 두 가지 단계

1. iOS 앱의 메서드 내에서 원하는 결과가 나오지 않을 경우에 에러를 발생하기

2. 메서드가 던진 에러를 잡아서(catch) 처리하기

에러도 타입을 통해 선언할 수 있으며 열거형으로 되어 있다.

에러 타입 선언하기

예를 들어, 원격 서버에 파일을 전송하는 메서드가 있다고 가정한다면, 이 메서드는 여러 원인으로 인하여 파일 전송에 실패할 가능성이 있다.

  • 네트워크 연결이 없거나 너무 느림
  • 전송할 파일을 찾지 못함
  • 파일의 사이즈가 큼

이 외에도 많은 경우가 있을 것이다. 이러한 모든 에러를 Error 프로토콜을 따르는 열거형 내에서 표현되도록 할 수 있다.
아래와 같이 에러 타입을 선언하면 에러가 발생할 때 사용할 수 있다.

// Error 프로토콜을 따르는 나만의 에러 타입 (열거형)
enum FileTransferError: Error {
    // 에러가 갖게 될 상황들을 값으로 정의함
    case noConnection
    case lowBandwidth
    case fileNotFound
    case TooBigSize
}

에러를 발생시킬 수 있는 상황 만들기

위에서는 에러 타입 선언을 통해 에러가 갖게 될 수 있는 상황을 값으로 정의했다. 이번엔 throw / guard 구문을 통해 에러가 발생할 수 있는 상황을 만들어볼 것이다.

guard 라는 키워드가 사용되었다고 해서 어려워 하지 말고, if문과의 반대 개념이라고 생각하면 쉽다.
즉 false일 때 내부 코드가 성립한다.


// 임의로 상황을 만들어보는 예제 코드
let connectionOK: Bool = true
let connectionSpeed: Double = 50.00
let fileFound: Bool = true
let fileSize: Int = 30


// 이 함수는 실행중에 오류가 발생할 수 있다. -> throws 키워드
func transferFile() throws {
    
    // connectionOK가 false이면 else 구문 실행 -> true이면 그냥 pass
    guard connectionOK else {
        throw FileTransferError.noConnection
    }
    
    guard connectionSpeed > 30 else {
        throw FileTransferError.lowBandwidth
    }
    
    guard fileFound else {
        throw FileTransferError.fileNotFound
    }
    
    guard fileSize < 20 else {
        throw FileTransferError.TooBigSize
    }
}

하지만 이렇게 발생할 수 있는 에러 상황을 생각하여 코드를 작성했음에도 미처 발견하지 못한 에러가 발생할 수 있다.

do-catch 구문을 사용하며 transferFile 메서드를 호출하여, 해당 에러에 대한 설명을 담고 있는 문자열 값을 반환한다.
또한 가장 마지막 catch 절은 에러에 대한 패턴 매칭이 이뤄지지 않은 상태에 대한 것으로, 앞선 catch 구문과 일치하지 않는 모든 에러를 처리할 수 있도록 해준다.


// let connectionOK: Bool = true
// let connectionSpeed: Double = 50.00
// let fileFound: Bool = true
// let fileSize: Int = 30

* 만약 connectionOK false 라면 다음 catch 구문을 통해 No Network Connction 이라는 문자열이 반환된다.

// 파일 전송을 "시도" 하고 결과를 문자열로 반환하는 함수
func sendFile() -> String {
    
    // do catch 했을때 어떤 에러가 오더라도 처리할 수 있도록
    do {
        try transferFile()
    } catch FileTransferError.noConnection {
        return "No Network Connction"
    } catch FileTransferError.lowBandwidth {
        return "File Transfer Speed too low"
    } catch FileTransferError.fileNotFound {
        return "File Not Found"
        // 에러 상황을 일부러 만들어서 그 상황을 확인할 수 있다.
        // 즉 놓친 에러를 직접 출력한다.
    } catch let error {
        print("error: \(error)")
        return "Unknown Error"
    }
    // 성공적으로 전송이 완료되었습니다.
    return "Successful transfer"
}

정리

  • 에러 타입들은 Error 프로토콜을 따르는 값들을 이용하여 생성되며, 열거형처럼 구현된다.
  • 에러를 던지는 메서드와 함수는 throw 키워드를 이용하여 선언한다.
  • guard와 throw 구문은 에러 타입을 기반으로 한 에러들을 던지기 위하여 메서드나 함수 코드 내에서 사용된다.
  • 메서드는 try 구문을 이용하여 호출되며, 반드시 do-catch 구문으로 감싼다.
  • do-catch 구문은 철저하게 나열된 catch 패턴으로 구성되며, 각각의 catch 구문은 특정 에러에 실행될 코드를 담는다.
profile
만드는 사람이 수고하면 쓰는 사람이 편하고 만드는 사람이 편하면 쓰는 사람이 수고롭다.

0개의 댓글