草庐IT

ios - MVVM 通用网络架构

coder 2023-07-16 原文

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

我遇到的这个特定架构的一个问题是,与 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()
        }
    }
}

然后在我的 View Controller 中我可以做的地方:

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

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

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

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

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 并以更好、更通用的方式促进网络,要么甚至是某种通用的基础协议(protocol)查看抽象整个过程的模型。

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

编辑:

根据@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")

它并没有完全解决 View Controller 和 View 模型应该如何相互交互的问题,但它肯定会将网络代码移至单点故障。

最佳答案

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

关于ios - MVVM 通用网络架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35866725/

有关ios - MVVM 通用网络架构的更多相关文章

  1. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  2. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  3. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  4. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  5. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  6. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  7. ruby - Ruby 和 Ruby on Rails 中的三层架构 - 2

    我是一名决定学习Ruby和RubyonRails的ASP.NETMVC开发人员。我已经有所了解并在RoR上创建了一个网站。在ASP.NETMVC上开发,我一直使用三层架构:数据层、业务层和UI(或表示)层。尝试在RubyonRails应用程序中使用这种方法,我发现没有关于它的信息(或者也许我只是找不到它?)。也许有人可以建议我如何在RubyonRails上创建或使用三层架构?附言我使用ruby​​1.9.3和RubyonRails3.2.3。 最佳答案 我建议在制作RoR应用程序时遵循RubyonRails(RoR)风格。Rails

  8. ruby - 检查网络文件是否存在,而不下载它? - 2

    是否可以在不实际下载文件的情况下检查文件是否存在?我有这么大的(~40mb)文件,例如:http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm这与ruby​​不严格相关,但如果发件人可以设置内容长度就好了。RestClient.get"http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm",headers:{"Content-Length"=>100} 最佳答案

  9. ruby - 404 未找到,但可以从网络浏览器正常访问 - 2

    我在这方面尝试了很多URL,在我遇到这个特定的之前,它们似乎都很好:require'rubygems'require'nokogiri'require'open-uri'doc=Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html"))putsdoc这是结果:/Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:353:in`open_http':404NotFound(OpenURI::HT

  10. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

随机推荐