简体   繁体   中英

ReactiveCocoa how to listen to change in data model properties

New to ReactiveCocoa here. I have a (MVVM) view model that represents a Newsfeed-like page, what's the correct way to listen to change in data model's properties? In the following example, startUpdate() constantly updates post . The computed properties messageToDisplay and shouldShowHeart drives some UI event.

struct Post {
    var iLiked: Bool
    var likes: Int
    ...
}

class PostViewModel: NSObject {
    private var post: Post

    var messageToDisplay: String {
        if post.iLiked { return ... }
        else { return .... }
    }

    var shouldShowHeart: Bool {
        return iLiked && likes > 10
    }

    func startUpdate() {
        // network request and update post
    }
    ...
}

It seems to me in order to make this whole thing reactive, I have to listen to each properties of Post and all computed properties? It doesn't look quite right to me.

Yes, you are right - you will have to listen to each property property of Post that you want to bind to the UI, but that is actually not that big of a deal.

I suggest you use ReactiveSwift Property and replace the computed properties like so:

final class PostViewModel {
  private let post: MutableProperty<Post>

  let messageToDisplay: Property<String>
  let shouldShowHeart: Property<Bool>

  func startUpdate() {
    // network request and update post by setting self.post.value = newPost
  }

  init(post: Post) {
    self.post = MutableProperty(post)
    self.messageToDisplay = self.post.map {
      if $0.iLiked { return "liked" }
      else { return "not liked" }
    }
    self.shouldShowHeart = self.post.map {
      $0.iLiked && $0.likes > 10
    }
  }
}

The only thing you change is the post (with each update of the post), hence that is a MutableProperty , but it is private and can only be changed by the PostViewModel .

The computed properties are replaced by Property (which are read-only) and since they derive their value from a post, they are mapped from the post MutableProperty

In your UI (I assume its a UITableViewCell for each post) you can bind these properties like this:

class PostTableViewCell: UITableViewCell {
  var message: UILabel!
  var heartIcon: UIImageView!

  func bind(post: PostViewModel) {
    message.reactive.text <~ post.messageToDisplay
    heartIcon.reactive.isHidden <~ post.shouldShowHeart.negate()
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM