TIL

[TIL] JSON으로 받은 에러 코드 통합 극복기(feat. RawRepresentable)

picel 2024. 8. 10. 16:11

요즘 토큰 갱신 로직 구현을 위해 네트워크 요청 로직을 통합하고 있는데요. 이 와중에 열거형으로 정의된 에러 타입을 통합 정의하는데 큰 어려움 있어서 오늘 포스팅은 이를 극복했던 일에 대해 작성해 보고자 합니다.

 

문제 상황

아래 코드는 네트워크 요청하는 메서드인데요. 아래 코드를 보시면 에러 타입을 Error 프로토콜을 준수하는 제너릭으로 구현되어 있습니다.

 

그리고 아래 코드를 보시면 Error 프로토콜을 준수하는 제너릭 타입 ErrorType은 initializer가 없다는 경고창이 뜹니다.

 

제가 위와 코드와 같이 에러 객체를 생성하려고 했던 이유는 아래 코드에서 아실 수 있듯이 모든 에러 타입이 원시값(Raw Value)을 가진 열거형으로 정의되어 있어 이 원시값을 가지고 어떤 네트워크 에러가 발생했는지 구분 짓기 위해서입니다. 

 

결국 문제는 어떻게 하면 원시값을 가진 열거형으로 정의되어 있는 에러 타입들을 통합할 수 있을지였습니다.

 

문제 원인 파악

여기저기 구글링을 한 결과 원시값을 가진 열거형 타입이 정의될 때 자동으로 추가되는 RawRepresentable 프로토콜을 준수하기 않았기 때문이었습니다.

 

그럼 여기서 RawRepresentable 프로토콜에 대해 간단히 알아보고 넘어가 보도록 하겠습니다.

RawRepresentable

A type that can be converted to and from an associated raw value. - Apple 공식문서

 

애플 공식문서를 살펴보시면 RawRepresentable 프로토콜은 위와 같이 '연결된 원시값으로(부터) 변환할 수 있는 유형입니다.'라고 정의되어 있습니다. 

 

처음에는 '음? 이게 무슨 말이지?' 싶었습니다.

그러다가 아래 코드 예제에서 보실 수 있듯이 애플 공식문서에 나와있는 코드 예제를 보고 바로 이해할 수 있었습니다. 

정의 그대로 원시값을 가지고 원시값을 가진 열거형 타입과 원시값 타입(RawValue)으로 서로 번갈아 전환할 수 있다는 의미였습니다.

enum Counter: Int {
    case one = 1, two, three, four, five
}

for i in 3...6 {
    print(Counter(rawValue: i))
}
// Prints "Optional(Counter.three)"
// Prints "Optional(Counter.four)"
// Prints "Optional(Counter.five)"
// Prints "nil"

 

더구나 위 코드의 Counter 열거형 구현부(정의 부분)에서 보실 수 있듯이 원시값으로 열거형을 정의하게 되면 RawRepresentable 프로토콜 준수가 컴파일러에 의해 자동으로 추가된다고 합니다. 바로 이 RawRepresentable 프르토콜을 준수하면 원시값을 가진 열거형을 정의할 수 있다는 의미인 것이죠.

RawRepresentable 내부 구조

개념을 명확히 하기 위해 RawRepresentable 프로토콜 내부 구조를 한번 살펴보겠습니다.

 

아래 코드를 살펴보시면 initializer를 통해 원시값을 입력을 통해 내부적으로 원시값이 저장된다는 것을 알 수 있습니다.

public protocol RawRepresentable<RawValue> {

    associatedtype RawValue

    init?(rawValue: Self.RawValue)

    var rawValue: Self.RawValue { get }
}

 

문제 해결

자 이제 그럼 제가 문제를 어떻게 해결했는지 말씀드려 보겠습니다.

 

우선 아래 이미지에서 보시는 바와 같이 Error 프로토콜을 준수하는 에러 제너릭 타입에 Protocol Composition을 사용하여 RawRepresentable 프로토콜도 준수하도록 해주었습니다.

 

그리고 해당 에러 제너릭 타입으로 원시값인 에러 코드를 활용해 에러 타입을 통합해 주었습니다.

아래 이미지를 보시면 에러 타입 객체 생성에 대한 경고창이 사라진 것을 확인해 보실 수 있습니다.

 

마치며

이번 문제를 해결하며 정말 당연하게 사용만 할 줄 알았던 원시값을 가진 열거형을 정의하였을 때 내부적으로 어떤 동작이 이루어지는지 새롭게 알 수 있었던 계기가 되었던 것 같습니다. 정말 개발의 세계는 파도파도 끝도 없는 것 같네요;;

 

아무튼 오늘도 여기까지 글 읽어주셔서 정말 감사합니다~!

참고 사이트

https://developer.apple.com/documentation/swift/rawrepresentable (Apple 공식문서 - RawRepresentable)