본문 바로가기
IOS App Programming/트러블 슈팅

[iOS/ UIKit] Error 핸들링 - 모든 에러를 하나의 형식으로 관리하자 feat.ReactorKit

by B_Tori 2024. 8. 2.

ReactorKit을 사용하면서 state에서 Error를 받고 있었고 여러 UseCase에서 다양한 Error들을 내뱉는데 어떻게 관리를 해야 할까 고민이 있었다.

한 개의 에러에 모든 에러를 몰아 넣을 수 없었다. 또한 NSError로 모두 정의하기에는 코드가 너무 지저분해 보였다.

각 클래스마다 에러를 지정하고 싶었고, 내가 정의하지 못한 시스템 에러 또한 잡아주기를 원했다.

그리고 각 에러마다 StatusCode와 간단한 설명이 있으면 좋겠다고 생각했다.

따라서 각 클래스마다 LocalizedError 프로토콜을 준수하는 에러 값들을 만들고 statusCode와 errorDescription을 따로 선언해 주었다.

예를 들면 다음과 같다

 

enum NaverLoginError: LocalizedError {
    case NotFountToken
    case serverError(code: Int, description: String)
    case decodingError
    case EmptyValue

    var statusCode: Int {
        switch self {
        case .NotFountToken:
            return -1001
        case .serverError(let code, _):
            return code
        case .decodingError:
            return -1002
        case .EmptyValue:
            return -1003
        }
    }

    var errorDescription: String? {
        switch self {
        case .NotFountToken:
            return "토큰이 없습니다."
        case .serverError(_, let message):
            return "서버 에러: \(message)"
        case .decodingError:
            return "데이터 디코딩 에러"
        case .EmptyValue:
            return "빈 응답값 전달"
        }
    }
}

 

그리고는 에러가 발생하는 상황에서 return Observable.error(NaverLoginError.decodingError) 다음과 같이 에러를 보내주었다.

 

하지만 한 가지 고민이 또 있었다.
Reactor의 State에서 var error: Error? 와 같이 받고 있었는데, 내가 정의하지 않고 그냥 내려보낸 기본 Error의 경우 statusCode와 errorDescription 이 없기 때문에 에러 메시지 출력 핸들링을 한 번에 처리할 수가 없었다.

 

나는 어떤 Error이든 statusCode와 errorDescription을 에러메시지로 출력하여 디버깅을 하고 싶었다.

 

따라서 기본 Error 타입에도 해당 두 변수들을 선언해 주기로 하였다.

extension Error {
    var statusCode: Int {
        return (self as? LocalizedError)?.statusCode ?? -9999
    }

    var errorDescription: String? {
        return (self as? LocalizedError)?.errorDescription ?? "An unexpected error occurred.: \(self.localizedDescription)"
    }
}

다음과 같이 익스텐션을 통해 선언을 하였다.

LocalizedError는 Error를 준수하는 프로토콜이기에 Error라고 통합하여 지칭할 수 있다.
따라서 들어온 Error가 LocalizedError라면 가지고 있는 값을 출력하고 아니라면 값이 없으므로 다른 지정값을 설정하여 출력하였다.

 

이렇게 해서 나는 리액터에서 어떤 에러든 굳이 분기문 처리하지 않아도 statusCode와 errorDescription을 이용해

디버깅 및 에러 핸들링을 할 수 있도록 처리하였다.

댓글