Search code examples
swiftuserdefaultsreactivekitswiftbond

ReactiveKit Bond KVO observe UserDefaults


I was previously using RxSwift and I decided I did not want to use it anymore and was able to convert everything over to Bond which I am much more familiar with. Since the new changes though to Bond v5, I cannot seem to figure out how to observe values in UserDefaults. The following code ends up giving me a fatal error.

userDefaults.reactive
      .keyPath(LocationManager.HomeLocationKey, ofType: String.self, context: .immediateOnMain)
      .map(self.initLocation(from:))
      .bind(to: self.homeLocation)

userDefaults is a reference to UserDefaults.standard and LocationManager.HomeLocationKey is a string. I am providing the initLocation function below as I know it will be asked for. Below that function I will post the error that I am receiving after the app starts up.

func initLocation(from string: String?) -> Location?
  {
    guard let dataString = string
      else { log.warning("Location data did not exist, returning nil"); return nil }

    let json = JSON.parse(dataString)

    return Location(from: json)
  }

Error:

fatal error: Could not convert nil to String. Maybe `dynamic(keyPath:ofExpectedType:)` method might be of help?): file /Users/sam/Documents/iOS Apps/Drizzle/Pods/Bond/Sources/Shared/NSObject+KVO.swift, line 58

Solution

  • It might not be obvious, but if the observed value can be nil, the ofType argument must be an Optional type. In your case, that would be:

    userDefaults.reactive
        .keyPath(LocationManager.HomeLocationKey, ofType: Optional<String>.self, context: .immediateOnMain)
        ...