SwiftyUserDefaults icon indicating copy to clipboard operation
SwiftyUserDefaults copied to clipboard

Have you ever thought of making some adjustments to RxSwift?

Open 0x30 opened this issue 7 years ago • 7 comments

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.
    }
}

0x30 avatar Aug 25 '18 03:08 0x30

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!

radex avatar Aug 30 '18 07:08 radex

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.

raphaeloliveira avatar Dec 05 '18 04:12 raphaeloliveira

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

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

DivineDominion avatar Apr 16 '19 08:04 DivineDominion

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

0x30 avatar Apr 17 '19 07:04 0x30

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 avatar Apr 17 '19 07:04 DivineDominion

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()
            }
        }
    }
}

DivineDominion avatar Apr 17 '19 08:04 DivineDominion

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()
      }
    }
  }
}

StevenSorial avatar Jan 26 '20 13:01 StevenSorial