【问题标题】:View Model Dependency Injection查看模型依赖注入
【发布时间】:2018-01-16 19:32:19
【问题描述】:

ItemDetailViewModel 使用以下签名进行初始化:

init(item: Item, didPressButton: Observable<Void>, api: FirebaseAPI)

它在ItemDetailViewController中初始化,它从源控制器的segue获得Item。我意识到ItemDetailViewController 在技术上是View,所以它不应该将Item 作为存储属性。我如何将Item 转移到ItemDetailViewModel?这也意味着ItemListViewController 不应该有一个selectedItem 存储属性可以在prepareFor(segue:) 中使用。

可能的解决方案

所以当CollectionView CellItemListViewController(源控制器)中被点击时,它应该通过绑定到存储Item 来触发ItemListViewModel,然后是perform segue。同时,在prepareForSegue 中,我使用ItemListViewModelItemDetailViewModel 初始化为Item。好的..这可以工作。

如何处理按钮点击,每次点击都会改变其图像?通过一个函数?

初始化view modelsinject dependencies 的正确方法是什么?

【问题讨论】:

  • 您的视图模型不应该与按钮点击有关。那是由视图或视图控制器来处理的。您应该按照您的建议创建ItemDetailViewModel,并通过segue 将其传递给ItemDetailViewController。当点击按钮时,视图控制器会收到该通知并更新ItemDetailViewModel
  • 好的,所以当我订阅按钮点击时,在订阅块内我将调用我的 viewModel 上的一个方法来处理行为。谢谢
  • didPressButton observable 不是按钮点击。相反,它是“视图模型做某事的原因”,这可能是也可能不是由于点击按钮。因此,视图模型不关心这个问题中的按钮点击。最好将可观察的按钮直接传递给视图模型,因为这会从视图控制器中删除逻辑。

标签: ios mvvm dependency-injection viewmodel rx-swift


【解决方案1】:

您有一个对象需要构建三个数据,但其中一个数据的来源与其他两个不同。这是使用高阶函数的好时机。

struct ItemDetailViewModel {
    static func factory(item: Item, api: FirebaseAPI) -> (_ action: Observable<Void>) -> ItemDetailViewModel {
        return { action in 
            return ItemDetailViewModel(item: item, didPressButton: action, api: api)
        }
    }
}

你的视图控制器会接受这个函数的结果:

class ItemDetailViewController: UIViewController {
    var viewModelFactory: (Observable<Void>) -> ItemDetailViewController = { _ in fatalError("factory called before provided.") }

    override func viewDidLoad() {
        super.viewDidLoad()
        let viewModel = viewModelFactory(myButton.rx.tap.asObservable())
        // bind output to view model
    }
}

然后在你之前的视图控制器中为 segue 做准备:

if let controller = segue.destinationViewController as? ItemDetailViewController {
    controller.viewModelFactory = ItemDetailViewModel.factory(item: anItem, api: api)
}

【讨论】: