简体   繁体   English

RxSwift订阅数据模型属性更改的正确方法

[英]RxSwift correct way to subscribe to data model property change

New to RxSwift here. 这里是RxSwift的新功能。 I have a (MVVM) view model that represents a Newsfeed-like page, what's the correct way to subscribe to change in data model's properties? 我有一个(MVVM)视图模型,该视图模型表示类似Newsfeed的页面,订阅数据模型属性更改的正确方法是什么? In the following example, startUpdate() constantly updates post . 在以下示例中, startUpdate()不断更新post The computed properties messageToDisplay and shouldShowHeart drives some UI event. 计算的属性messageToDisplayshouldShowHeart驱动一些UI事件。

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 turn each properties of Post and all computed properties into Variable ? 在我看来,为了使整个过程具有反应性,我必须将Post每个属性和所有计算的属性转换为Variable It doesn't look quite right to me. 在我看来,这不太正确。

// Class NetworkRequest or any name //类NetworkRequest或任何名称

static func request(endpoint: String, query: [String: Any] = [:]) -> Observable<[String: Any]> {
    do {
        guard let url = URL(string: API)?.appendingPathComponent(endpoint) else {
            throw EOError.invalidURL(endpoint)
        }

        return manager.rx.responseJSON(.get, url)
            .map({ (response, json) -> [String: Any] in
                guard let result = json as? [String: Any] else {
                    throw EOError.invalidJSON(url.absoluteString)
                }
                return result
            })
      } catch {
        return Observable.empty()
      }
}

static var posts: Observable<[Post]> = {
    return NetworkRequest.request(endpoint: postEndpoint)
        .map { data in
            let posts = data["post"] as? [[String: Any]] ?? []
            return posts
                .flatMap(Post.init)
                .sorted { $0.name < $1.name }
        }
        .shareReplay(1)
}()


class PostViewModel: NSObject {
    let posts = Variable<[Post]>([])
    let disposeBag = DisposeBag()
    override func viewDidLoad() {
      super.viewDidLoad()

      posts
       .asObservable()
       .subscribe(onNext: { [weak self] _ in
         DispatchQueue.main.async {
            //self?.tableView?.reloadData() if you want to reload all tableview
            self.tableView.insertRows(at: [IndexPath], with: UITableViewRowAnimation.none) // OR if you want to insert one or multiple rows.
            //OR update UI
         }
      })
      .disposed(by: disposeBag)



      posts.asObservable()
     .bind(to: tableView.rx.items) { [unowned self] (tableView: UITableView, index: Int, element: Posts) in
        let cell = tableView.dequeueReusableCell(withIdentifier: "postCell") as! PostCell
//for example you need to update the view model and cell with textfield.. if you want to update the ui with a cell then use cell.button.tap{}. hope it works for you.
        cell.textField.rx.text
            .orEmpty.asObservable()
            .bind(to: self.posts.value[index].name!)
            .disposed(by: cell.disposeBag)
        return cell
    }

      startDownload()
  }
}

func startDownload {
    posts.value = NetworkRequest.posts
}

If you want to change anything then use subscribe, bind, concat .. There are many methods and properties which you can use. 如果要更改任何内容,请使用subscription,bind,concat ..您可以使用许多方法和属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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