본문 바로가기
Swift

[Swift] 에러처리(Result Type)

by Jimmy_iOS 2023. 6. 6.

에러 처리는 프로그래밍에서 중요한 부분 중 하나입니다.

이번에는 Swift에서 에러를 처리하는 방법을 알아보겠습니다.

일반적인 에러 처리와 Result Type의 차이

Swift에서는 일반적으로 throws를 사용하여 에러를 처리합니다. 하지만 최근에는 Result Type을 이용한 에러 처리 방식도 좋은 방법으로 이용되고 있습니다. 먼저, throws와 Result Type의 차이에 대해 알아보겠습니다.

throws를 사용하면 함수에서 에러를 던지게 됩니다. 이 때, do-catch문을 사용하여 에러를 처리합니다. 하지만, Result Type을 사용하면 함수에서 Result라는 타입을 반환하며, 성공 여부와 에러의 내용을 함께 전달할 수 있습니다.

에러를 정의하고 사용하는 방법

에러를 정의하고 사용하는 방법에 대해 알아보겠습니다. 먼저, 에러를 정의할 때는 Error 프로토콜을 채택하는 열거형을 사용합니다.

enum SomeError: Error {
    case aError
    case bError

    var localizedDescription: String {
        switch self {
        case .aError:
            return "a에러 방출"
        case .bError:
            return "b에러 방출"
        }
    }
}

위와 같이 Error 프로토콜을 채택하는 열거형을 만들고, 각각의 케이스에 대해 메시지를 지정할 수 있습니다.

이제, 에러를 던지는 함수를 정의해보겠습니다.

func throwingFunc() throws {
    throw SomeError.aError
}

위와 같이 throws 키워드를 사용하여 함수에서 에러를 던지게 됩니다.

다음으로, 에러를 처리해보겠습니다.

do {
    try throwingFunc()
} catch let error as SomeError {
    print(error.localizedDescription) //a에러 방출
}

do-catch문에서 try 키워드를 사용하여 에러를 처리합니다. catch 블록에서 에러 타입을 지정하여, 해당 타입의 에러가 발생했을 경우에만 처리하게 됩니다.

Result Type

Result Type은 Swift 5에서 추가된 기능입니다. Result Type은 함수에서 성공 여부와 에러의 내용을 함께 반환할 수 있도록 합니다.

enum Result<Success, Failure> where Failure: Error {
    case success(Success)
    case failure(Failure)
}

Result 타입은 제네릭 타입으로, Success와 Failure 두 개의 제네릭 타입을 받습니다. Failure는 Error 프로토콜을 채택하는 타입이어야 합니다.

에러를 정의하는 방법은 일반적인 방법과 동일합니다.

enum HeightError: Error {    //에러 프로토콜 채택 (약속)
    case maxHeight
    case minHeight
}

다음으로, Result Type을 사용하여 에러를 처리하는 방법에 대해 알아보겠습니다.

func resultTypeCheckingHeight(height: Int) -> Result<Bool, HeightError> {

    if height > 190 {
        return Result.failure(HeightError.maxHeight)
    } else if height < 130 {
        return Result.failure(HeightError.minHeight)
    } else {
        if height >= 160 {
            return Result.success(true)
        } else {
            return Result.success(false)
        }
    }
}

let result = resultTypeCheckingHeight(height: 200)

switch result {
case .success(let data):
    print("결과값은 \\\\(data)입니다.")
case .failure(let error):
    print(error)
}

위 코드에서 resultTypeCheckingHeight 함수는 Result<Bool, HeightError> 타입을 반환합니다. Result 타입에서 success 케이스는 성공한 경우에 대한 정보를 전달하며, failure 케이스는 실패한 경우에 대한 정보를 전달합니다.

switch문에서 success 블록과 failure 블록을 각각 처리합니다.

네트워킹 코드에서 Result Type

마지막으로, 네트워킹 코드에서 Result Type을 사용하는 방법에 대해 알아보겠습니다.

func performRequest2(with urlString: String, completion: @escaping (Result<Data,NetworkError>) -> Void) {

    guard let url = URL(string: urlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if error != nil {
            print(error!)                     // 에러가 발생했음을 출력
            completion(.failure(.someError))  // 실패 케이스 전달
            return
        }

        guard let safeData = data else {
            completion(.failure(.someError))   // 실패 케이스 전달
            return
        }

        completion(.success(safeData))      // 성공 케이스 전달

    }.resume()
}

performRequest2(with: "주소") { result in
    switch result {
    case .failure(let error):
        print(error)
    case .success(let data):
        // 데이터 처리 관련 코드
        break
    }
}

위 코드에서 performRequest2 함수는 Result<Data, NetworkError>를 반환합니다. 이를 이용하여 네트워크 요청에 대한 성공 여부와 에러의 내용을 함께 전달합니다.

switch문에서 success 블록과 failure 블록을 각각 처리합니다.

결론

이번 글에서는 Swift에서 에러 처리하는 방법에 대해 알아보았습니다. Result Type은 최근에 추가된 기능으로, 성공 여부와 에러의 내용을 함께 전달할 수 있어 편리합니다. 에러 처리는 프로그래밍에서 중요한 부분이므로, 적절한 방법으로 처리하는 것이 중요합니다.