0

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.

Jack Guo
  • 3,959
  • 8
  • 39
  • 60

1 Answers1

1

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()
  }
}
MeXx
  • 3,357
  • 24
  • 39