首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MVVM通用网络架构

MVVM通用网络架构
EN

Stack Overflow用户
提问于 2016-03-08 19:56:33
回答 1查看 3.4K关注 0票数 9

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

我在这个特殊的架构中遇到的一个问题是,像MVC一样,仍然没有一个清晰的地方或方法来组织网络代码。举个简单的例子:

代码语言:javascript
复制
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()
        }
    }
}

然后在我的视图控制器中,我可以这样做:

代码语言:javascript
复制
self.viewModel.posts <~ self.viewModel.fetchPosts().on(next: { _ in self.collectionView.reloadData() })

对我来说,使用MVVM的整个目的是不将视图和视图控制器(我称之为视图表示层)暴露给任何网络代码,但我仍然需要一种方法来观察新内容已经被获取,而不知道细节,只是成功获取发生了。我想它看起来应该是这样的:

代码语言:javascript
复制
self.viewModel.contentUpdatedSignal.observeNext { _ in self.collectionView.reloadData() }

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

代码语言:javascript
复制
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的建议,我将一些网络代码移动到我的模型类中,但仅作为静态方法:

代码语言:javascript
复制
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模型:

代码语言:javascript
复制
User.get("myUserID")

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

EN

回答 1

Stack Overflow用户

发布于 2016-03-08 20:34:22

我在使用MVVM或RAC方面不是很高级,但从我使用的网络代码来看,应该是在模型部分,然后是在视图模型部分观察结果的方法(类似于" fetchPosts ()"),并且在视图部分调用fetchPosts方法。我推荐你使用this blog post获取更多信息。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35866725

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档