使ObservableObject订阅自定义PropertyWrapper

时间:2019-12-08 13:42:01

标签: swift swiftui combine

我写了一个自定义的PropertyWrapper,它试图包装UserDefaults,同时还赋予它们与@Published变量相同的行为。除了ObservableObject在不遵守UserDefaults本身的情况下不会传播更改之外,几乎可以正常工作。

我无法将objectWillChange引用传递给@Setting初始化,因为selfSettings.init期间不可用...

我想知道@Published是如何做到的。

import Combine
import Foundation

class Settings: ObservableObject {

// Trying to avoid this:
/////////////////////////////////////////////
  let objectWillChange = PassthroughSubject<Void, Never>()
  private var didChangeCancellable: AnyCancellable?
  private init(){
    didChangeCancellable = NotificationCenter.default
      .publisher(for: UserDefaults.didChangeNotification)
      .map { _ in () }
      .receive(on: DispatchQueue.main)
      .subscribe(objectWillChange)
  }
/////////////////////////////////////

  static var shared = Settings()

  @Setting(key: "isBla") var isBla = true
}


@propertyWrapper
public struct Setting<T> {

  let key: String
  let defaultValue: T

  init(wrappedValue value: T, key: String) {
    self.key = key
    self.defaultValue = value
  }

  public var wrappedValue: T {
    get {
      let val = UserDefaults.standard.object(forKey: key) as? T
      return val ?? defaultValue
    }
    set {
      objectWillChange?.send()
      publisher?.subject.value = newValue
      UserDefaults.standard.set(newValue, forKey: key)
    }
  }

  public struct Publisher: Combine.Publisher {

    public typealias Output = T

    public typealias Failure = Never

    public func receive<Downstream: Subscriber>(subscriber: Downstream)
      where Downstream.Input == T, Downstream.Failure == Never {
        subject.subscribe(subscriber)
    }

    fileprivate let subject: Combine.CurrentValueSubject<T, Never>

    fileprivate init(_ output: Output) {
      subject = .init(output)
    }
  }

  private var publisher: Publisher?

  internal var objectWillChange: ObservableObjectPublisher?

  public var projectedValue: Publisher {
    mutating get {
      if let publisher = publisher {
        return publisher
      }
      let publisher = Publisher(wrappedValue)
      self.publisher = publisher
      return publisher
    }
  }
}

0 个答案:

没有答案