MVVM通用网络架构

时间:2016-03-08 11:56:33

标签: ios swift mvvm architecture network-programming

我使用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() }

与此同时,我也不想在使用<~时失去将信号和信号生成器绑定到可变属性的能力。

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")

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

1 个答案:

答案 0 :(得分:1)

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

相关问题