iOS) Property Wrapper 로 User Defaults 리펙토링하기

1 minute read

내용

  • Property Wrapper 를 사용하여 UserDefaults 읽고 쓰고 삭제하는 매커니즘을 캡슐화 해보자.

Swift-Evolution

swift-evolution 에서 property wrappers 를 소개하면서 예시로 UserDefaults 의 매커니즘을 캡슐화하여 사용하는 예시 코드를 소개했다. 살펴보자!

swift-evolution/0258-property-wrappers.md at main · apple/swift-evolution

프로퍼티 래퍼는 user defaults 와 같은 string-keyed 데이터에 대한 typed property 들을 제공하는데 사용할 수 있습니다. wrapper type 에서 데이터를 추출하는 매커니즘을 아래처럼 캡슐화할 수 있습니다.

@propertyWrapper
struct UserDefault<T> {
  let key: String
  let defaultValue: T
  
  // ✅ Userdefaults 로 값을 찾을 때 없다면, defaultValue 를 반환.
  // 그렇기 때문에 wrappedValue 는 옵셔널이 아님.
  var wrappedValue: T {
    get {
      return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
    }
    set {
      UserDefaults.standard.set(newValue, forKey: key)
    }
  }
}

enum GlobalSettings {
  @UserDefault(key: "FOO_FEATURE_ENABLED", defaultValue: false)
  static var isFooFeatureEnabled: Bool
  
  @UserDefault<Bool>(key: "BAR_FEATURE_ENABLED", defaultValue: false)
  static var isBarFeatureEnabled
}

다음과 같은 방법으로도 사용이 가능하다. 캡슐화 방식은 결국 얼마나 비슷한 기능을 묶고, 외부에서 내부의 연산과정을 얼마나 잘 숨겼냐에 따라 구현방식이 다를 수 있다.

@propertyWrapper
struct UserDefault<T> {
  // ✅ backtick 을 사용하여 예약어를 변수로 사용.
    private var `default` = UserDefaults.standard
    private let key: String

  // ✅ 생성자를 통해 key 초기화.
    init(key: String) {
        self.key = key
    }

  // ✅ UserDefaults 로 값을 찾을 때 없다면 nil 반환.
  // 호출 부분에서 nil 에 대한 대응을 해주어야 함.
  var wrappedValue: T? {
    get {
            self.default.object(forKey: key) as? T
        }
        set {
            self.default.setValue(newValue, forKey: key)
        }
    }
}

/// 선언한 propertyWrapper를 사용하면 아래와 같다. 
final class UserManager {
    @UserDefault<String>(key: "usesTouchID") 
    private var usesTouchID

  // ✅ usesTouchID 는 String? 타입입니다.
  // @UserDefault(key: "usesTouchID") 
    // private var usesTouchID: String?
}

// ✅ 다음과 같이 호출하는 곳에서 nil-Coalescing Operator(nil 병합 연산자)이나 옵셔널 바인딩 등을 활용하여 대응할 수 있다.
let usesTouchID: String = UserManager().usesTouchID ?? ""

참고

후로훠티 래퍼 · Discussion #5 · 28th-SOPT-iOS-CloneCoding/weakselfWang

swift-evolution/0258-property-wrappers.md at main · apple/swift-evolution

Categories:

Updated: