Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] RawRepresentable 프로토콜 (enum의 rawValue 커스텀 방법) 본문

iOS 응용 (swift)

[iOS - swift] RawRepresentable 프로토콜 (enum의 rawValue 커스텀 방법)

jake-kim 2022. 2. 14. 02:00

enum에서 RawValue를 커스텀할 수 있는 방법?

  • 만약 rawValue를 가져올 때 side effect 처리를 추가하고 싶은 경우?
  • 아래처럼 rawValue를 '='이나 implicit  raw value로 지정되는게 아닌 직접 커스텀하고 싶은 경우?
enum Person: String {
  case jake = "jake"
  case kim // implicit raw value of "kim"
}

let person = Person.jake
print(person.rawValue) // "jake"

RawRepresentable을 사용하여 커스텀 가능

RawRepresentable 이란?

  • swift에서의 enum은 하나 이상의 `associated value`를 갖을 수 있는데, 이 값의 rawValue에 대한 정의하는 프로토콜
  • enum에서의 associated rawValue 값을 정의하는 타입

  • 보통 RawRepresentable은 컴파일러가 자동으로 추가해주므로 모든 raw value값이 컴파일 타임에 결정
    • enum에서의 rawValue 예시
      enum Person: String {
        case jake = "jake"
        case kim // implicit raw value of "kim"
      }
      
      let person = Person.jake
      print(person.rawValue) // "jake"

RawRepresentable 사용 방법

  • 컴파일러가 RawRepresentable을 자동으로 추가해주지만, RawRepresentable을 extension으로 직접 구현하면 사용자 정의가 가능
    • 단, extension으로만 추가하지 않으면 컴파일 에러 발생
  • RawRepresentable 준수
    • RawValue 타입 정의와 init?(rawValue:), rawValue 프로퍼티 정의 필요
      RawRepresentable 프로토콜

ex) usecase: 아래처럼 Number라는 enum이 있는데, Number.init(rawValue:) 초기화 값에 아무런 값을 넣으면 자동으로 odd나 event으로 초기화 되게 하고 싶은 경우

 Number.init(rawValue:123) -> .odd로 초기화

enum Number {
  case odd(Int)
  case even(Int)
}
  • extension으로 RawRepresentable 준수
    extension Number: RawRepresentable {
      typealias RawValue = Int
      
      // case값을 가지고 rawValue값을 리턴
      var rawValue: Int {
      }
      
      // rawValue를 가지고 case 값을 초기화
      init?(rawValue: Int) {
      }
    }​
  • rawValue 구현
    // case값을 가지고 rawValue값을 리턴
    var rawValue: Int {
      switch self {
      case
        let .odd(value),
        let .even(value)
      :
        return value
      }
    }​
  • init?(rawValue: Int) 구현
    // rawValue를 가지고 case 값을 초기화
    init?(rawValue: Int) {
      if rawValue % 2 == 0 {
        print("짝수!! \(rawValue)") // side effect
        self = .even(rawValue)
      } else {
        print("홀수!! \(rawValue)") // side effect
        self = .odd(rawValue)
      }
    }​

* 전체 코드

enum Number {
  case odd(Int)
  case even(Int)
}

extension Number: RawRepresentable {
  typealias RawValue = Int
  
  // case값을 가지고 rawValue값을 리턴
  var rawValue: Int {
    switch self {
    case
      let .odd(value),
      let .even(value)
    :
      return value
    }
  }
  
  // rawValue를 가지고 case 값을 초기화
  init?(rawValue: Int) {
    if rawValue % 2 == 0 {
      print("짝수!! \(rawValue)") // side effect
      self = .even(rawValue)
    } else {
      print("홀수!! \(rawValue)") // side effect
      self = .odd(rawValue)
    }
  }
}
  • 사용하는 쪽
    class ViewController: UIViewController {
      override func viewDidLoad() {
        super.viewDidLoad()
        
        let number = Number.init(rawValue: 123) // 이렇게 넣어도 알아서 odd로 초기화
        print(number)
        /*
         홀수!! 123
         Optional(ExRawValue.Number.odd(123))
         */
      }
    }​

* 참고

https://nshipster.com/rawrepresentable/

https://jcsoohwancho.github.io/2019-08-19-enum-%EB%8D%94-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0-CaseIterable,-RawPresentable,-

 

https://developer.apple.com/documentation/swift/rawrepresentable

Comments