sunshinejr / SwiftyUserDefaults

Modern Swift API for NSUserDefaults
http://radex.io/swift/nsuserdefaults/static
MIT License
4.85k stars 366 forks source link

Have you ever thought of making some adjustments to RxSwift? #165

Open 0x30 opened 6 years ago

0x30 commented 6 years ago

Have you ever thought of making some adjustments to RxSwift?

Like the following?

import RxCocoa
import RxSwift

/// Maintain life cycle UnsafeRawPointer
private var keeplive = "defaultkeeplive"

extension DefaultsKey{

    private var keepLiveObservalue:NSObject?{
        set(newvalue){ objc_setAssociatedObject(self, &keeplive, newvalue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } // Save keep live obj
        get{ return nil } // In order to save trouble...
    }

    /// Make a Binder according to the DefaultsKey provided.
    /// Binder Value Type == DefailtsKey ValueType
    var binder:Binder<ValueType>{
        let keepliveobj = NSObject()
        self.keepLiveObservalue = keepliveobj
        return Binder(keepliveobj) { _, value in
            Defaults[self] = value
        }
    }

    /// Make a Observable according to the DefaultsKey provided.
    /// Observable Element Type == DefailtsKey ValueType
    var observable:Observable<ValueType>{
        return UserDefaults.standard.rx.observe(ValueType.self, self._key)
            .filter{ $0 != nil }.map{ $0! } // If you use RxOptional, it will be better.
    }
}
radex commented 6 years ago

Rx is fun! I think it would be inappropriate to have this as part of SwiftyUserDefaults, because there shouldn't be a forced dependency on RxSwift, but as an extension library — yeah!

raphaeloliveira commented 5 years ago

Extending on that, I'm facing issues because I'm using ReactiveSwift and its reactive extension won't use the default value provided on DefaultsKey initialiser. I'm happy to adapt my code but would be convenient if internal let defaultValue: ValueType? property would be public instead of internal.

DivineDominion commented 5 years ago

I think making defaultValue public and read-only will be useful, too!

Also @0x30 what about an Rx extension in https://github.com/RxSwiftCommunity/ ?

0x30 commented 5 years ago

Ok, I may not express it very clearly, I hope I can get a configuration similar to Moya.

  s.subspec "ReactiveSwift" do |ss|
    ss.source_files = "Sources/ReactiveMoya/"
    ss.dependency "Moya/Core"
    ss.dependency "ReactiveSwift", "~> 5.0"
  end

  s.subspec "RxSwift" do |ss|
    ss.source_files = "Sources/RxMoya/"
    ss.dependency "Moya/Core"
    ss.dependency "RxSwift", "~> 4.0"
  end
DivineDominion commented 5 years ago

Aha! Well, this would require the SwiftyUserDefaults maintainers to care for the reactive extensions, which is now only 2 people it seems. If they don't want to, and someone else starts with a RxSwiftCommunity repo, the extension can be maintained by a larger group of Rx fans, which makes the extension more resilient in the long term. (But will require you to import RxSwiftyUserDefaults on top of this library.)

DivineDominion commented 5 years ago

This is how I started in my app during the v4.0 transition, btw:

extension Reactive where Base: UserDefaults {
    func observe<T: DefaultsSerializable>(key: DefaultsKey<T>, options: NSKeyValueObservingOptions = [.old, .new]) -> RxSwift.Observable<T.T?> {
        return Observable.create { observer -> Disposable in
            let token = self.base.observe(key: key, options: options) { update in
                observer.onNext(update.newValue)
            }
            return Disposables.create {
                token.dispose()
            }
        }
    }
}
StevenSorial commented 4 years ago

This is how I started in my app during the v4.0 transition

is there an updated sample for v5?

Edit: got it to work properly:

extension DefaultsAdapter {
  func observe<T: DefaultsSerializable>(_ key: DefaultsKey<T>,
                                        options: NSKeyValueObservingOptions = [.old, .new]
  ) -> RxSwift.Observable<DefaultsObserver<T>.Update> where T == T.T {
    Observable.create { observer in
      let token = self.observe(key, options: options) { update in
        observer.onNext(update)
      }
      return Disposables.create {
        token.dispose()
      }
    }
  }

  func observe<T: DefaultsSerializable>(_ keyPath: KeyPath<KeyStore, DefaultsKey<T>>,
                                        options: NSKeyValueObservingOptions = [.old, .new]
  ) -> RxSwift.Observable<DefaultsObserver<T>.Update> where T == T.T {
    Observable.create { observer in
      let token = self.observe(keyPath, options: options) { update in
        observer.onNext(update)
      }
      return Disposables.create {
        token.dispose()
      }
    }
  }
}