Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxSwift MVVM How to Set up View Model With Item Manager?

Tags:

swift

rx-swift

Say I have the following SwiftRx (2.0.0-beta.4) MVVM situation:

I have 4 things:

  • ItemListViewController
  • ItemsViewModel
  • ItemsManager
  • Item

ItemsManager has a func called items() that will return Items in an observable RxSwift way.

ItemsViewModel only needs to pass the items on up for now. Later maybe apply display logic on an Item attribute for the View Controller's sake (like displaying a date correctly.)

ItemListViewController will put the items in a table, one Item per row.

An Item has 4 attributes (like an identifier, date, ...) that will be displayed in the table row cell.

How does one set it up in the ItemsViewModel and ItemsManager so that when items are added, removed, changed in the manager that they go through the ItemsViewModel?

From reading the documentation and looking at the Rx.playground, it seems like the thing to use for now is an RxSwift PublishSubject< Item > or maybe an RxSwift map that is somehow subscribed to the manager's items()

How to do this well?

The ItemsManager has something like this right now:

func items() -> Observable<Item> {
    // placeholder for now
    return [Item(identification: "123", content: ""), Item(identification: "456", content:""), Item(identification: "789", content:"")].toObservable()
}

The View Model has this in it:

let items = Variable(/* how to subsribe to the items in the manager? */)
like image 657
finneycanhelp Avatar asked Dec 08 '15 23:12

finneycanhelp


1 Answers

A contrived solution aka something which demonstrates a general approach and is simpler to understand is below:

import UIKit
import RxSwift
import RxCocoa

struct Item {

    let identification: String
    let content: String
}

struct ItemsManager {

    let items: Variable<[Item]> = Variable<[Item]>(
        [Item(identification: "some id1", content: "some content"),
        Item(identification: "some id2", content: "some more content")]
    )
}

struct ItemsViewModel {

    let itemsManager = ItemsManager()

    let myItems:Observable<[String]>

    init() {

        myItems = itemsManager.items
        .map({ someArrayOfItems in
            return someArrayOfItems.map {$0.content }
        })
    }
}

class ItemListViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    let itemsViewModel = ItemsViewModel()

    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        itemsViewModel.myItems
            .bindTo(tableView.rx_itemsWithCellIdentifier("itemListCell")) { (row, element, cell) in

                guard let myCell: UITableViewCell = cell else {
                    return
                }

                myCell.textLabel?.text = element
            }
            .addDisposableTo(disposeBag)

    }
}
like image 112
finneycanhelp Avatar answered Oct 22 '22 12:10

finneycanhelp