【发布时间】: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 <~ 上的可变属性的能力。
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