【问题标题】:MVVM generic networking architectureMVVM 通用网络架构
【发布时间】:2016-06-22 08:38:25
【问题描述】:

我使用 Model View ViewModel 范例开发 iOS 应用程序来构建我的视图控制器并表示它们的数据。与ReactiveCocoa 结合使用是一个强大的工具;视图控制器变得不那么臃肿,视图模型更容易测试,并且关注点分离清晰。

我对这种特定架构的一个问题是,像 MVC 一样,仍然没有一个明确的位置或方法来构建网络代码。 举个简单的例子:

class HomepageViewModel {
    var posts: MutableProperty<[Post]> = MutableProperty([])

    func fetchPosts() -> SignalProducer<[Post], NSError> {
        return SignalProducer { observer, disposable in
            // do some networking stuff
            let posts = ....
            observer.sendNext(posts)
            observer.sendCompleted()
        }
    }
}

然后在我的视图控制器中我可以做的地方:

self.viewModel.posts <~ self.viewModel.fetchPosts().on(next: { _ in self.collectionView.reloadData() })

对我来说,使用 MVVM 的全部意义在于不将视图和视图控制器(我称之为视图表示层)暴露给任何网络代码,但我仍然需要一种方法来观察新的在不知道具体细节的情况下提取了内容,只是发生了成功的提取。我想这看起来像:

self.viewModel.contentUpdatedSignal.observeNext { _ in self.collectionView.reloadData() }

同时,我也不想失去将信号和信号生产者绑定到我 using &lt;~ 上的可变属性的能力。

class ViewModel {
    let someProperty = MutableProperty<[SomeModel]>([])
    var (contentUpdatedSignal, observer) = Signal.pipe()
    init() {
        self.someProperty <~ self.fetchContent().on(next: { _ in observer.sendNext() }
    }

    func fetchContent() -> SignalProducer<[SomeModel], NSError> {
        // do some fun stuff
    }
}

这样做的方法稍微好一点,但它仍然使用副作用来在信号观察器上发送下一个事件,如果您使用公共 ViewModel 基类,则必须公开该观察器以便子类可以用。

我正在寻找可以对 MVVM 架构进行的任何改进,或者对架构本身进行更改,使其不再是 MVVM,并以更好和更通用的方式促进网络,或者甚至是某种通用基础协议查看将整个过程抽象出来的模型。

对我来说,尽可能通用,同时尽可能少地公开有关视图模型的信息是关键。理想情况下,我希望每个视图控制器与视图模型的交互方式与网络工作方式完全相同。

编辑:

根据@lonut 的建议,我将一些网络代码移到了我的模型类中,但仅作为静态方法:

import Foundation
import ReactiveCocoa
import Moya

protocol RESTModel {
    typealias Model

    static func create(parameters: [NSObject: AnyObject]?) -> SignalProducer<Model, Moya.Error>
    static func find()  -> SignalProducer<Model, Moya.Error>
    static func get(id: String) -> SignalProducer<Model, Moya.Error>
    static func update(id: String) -> SignalProducer<Model, Moya.Error>
    static func remove(id: String) -> SignalProducer<Model, Moya.Error>

}

extension RESTModel {
    static func create(parameters: [NSObject: AnyObject]? = nil) -> SignalProducer<Self.Model, Moya.Error> {
        return SignalProducer.empty
    }
    static func find() -> SignalProducer<Self.Model, Moya.Error> {
        return SignalProducer.empty
    }
    static func get(id: String) -> SignalProducer<Self.Model, Moya.Error> {
        return SignalProducer.empty
    }
    static func update(id: String) -> SignalProducer<Self.Model, Moya.Error> {
        return SignalProducer.empty
    }
    static func remove(id: String) -> SignalProducer<Self.Model, Moya.Error> {
        return SignalProducer.empty
    }
}

这种方式模型可以随意实现网络调用,这有利于抽象出具体的 Moya 网络调用、响应对象映射等实现细节。

假设你有一个User 模型:

User.get("myUserID")

它并没有完全解决视图控制器和视图模型应该如何交互的问题,但它确实将网络代码移动到了单点故障。

【问题讨论】:

    标签: ios swift mvvm architecture network-programming


    【解决方案1】:

    我在使用 MVVM 或 RAC 方面不是很先进,但从我玩过的网络代码应该在模型部分中,然后有一种方法可以在视图模型部分中观察结果(类似于“fetchPosts ()") 并在视图部分调用 fetchPosts 方法。我建议您this blog post 了解更多信息。

    【讨论】:

    • 我不同意,因为模型应该只是一个数据表示。虽然可以,但是只要取数据的方法是类方法,而不是实例方法。
    • 我在考虑一个像 PostSearch 这样的模型,它有网络代码,而不是 Post 模型也应该包含网络代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-02
    • 2021-09-11
    • 2010-10-10
    相关资源
    最近更新 更多