Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to observe property changed in Swift with ReactiveCocoa

I am writing Swift with the new ReactiveCocoa + ReactiveSwift. I am trying to do something like the following (in ReactiveCocoa 2.5) with the new ReactiveCocoa framework:

[[RACObserve(user, username) skip:1] subscribeNext:^(NSString *newUserName) {
    // perform actions...
}];

After some researches, I still could not figure out how to do it. Please help! Thank you very much!

like image 279
Robert Huang Avatar asked Dec 02 '22 12:12

Robert Huang


1 Answers

Your snippet works via KVO which is still possible with the most recent RAC/RAS in Swift, but is not the recommended way anymore.

Using Property

The recommended way is to use Property which holds a value and can be observed.

Here is an example:

struct User {
  let username: MutableProperty<String>
  init(name: String) {
    username = MutableProperty(name)
  }
}

let user = User(name: "Jack")

// Observe the name, will fire once immediately with the current name
user.username.producer.startWithValues { print("User's name is \($0)")}
// Observe only changes to the value, will not fire with the current name
user.username.signal.observeValues { print("User's new name is \($0)")}

user.username.value = "Joe"

which will print

User's name is Jack

User's name is Joe

User's new name is Joe

Using KVO

If for some reason you still need to use KVO, heres how you can do that. Keep in mind, that KVO only works on explicit subclasses of NSObject, and if the class is written in Swift, the property needs to be annotated with @objc and dynamic!

class NSUser: NSObject {
  @objc dynamic var username: String
  init(name: String) {
    username = name
    super.init()
  }
}

let nsUser = NSUser(name: "Jack")

// KVO the name, will fire once immediately with the current name
nsUser.reactive.producer(forKeyPath: "username").startWithValues { print("User's name is \($0)")}
// KVO only changes to the value, will not fire with the current name
nsUser.reactive.signal(forKeyPath: "username").observeValues { print("User's new name is \($0)")}

nsUser.username = "Joe"

which will print

User's name is Optional(Jack)

User's new name is Optional(Joe)

User's name is Optional(Joe)

like image 191
MeXx Avatar answered Mar 04 '23 10:03

MeXx