iOS开发:关于Moya之上的Request层

我遇到的问题

我在做项目开发的时候,遇到了这样两个页面:

  • A页面是一个关注列表页面,有列表接口与关注与取消关注接口
  • B页面是一个他人主页页面,有他人信息接口与关注与取消关注接口

可以看到,这两个页面都会用到关注与取消关注接口:

一般1个ViewController会对应1个ViewModel,而ViewModel可能会对应多个网络请求:

如果我们项目简单,直接多个网络请求放在一个ViewModel中,没有问题。

但是随着项目的复杂度增加,我们可能会遇到这样的问题:ViewModel中有多个网络请求,而其中某个或者某个网络请求可能会在多个ViewModel中复用。

使用继承可以吗?

有人可能会思考,那么就将业务复用接口写到一个基类ViewModel中继承即可,比如下面这样的伪代码:

swift 复制代码
class 他人主页ViewModel: 关注列表ViewModel {
    /// 新写一个他人信息接口
}

那么此时,他人主页ViewModel实际上包含了3个接口:

  • 列表接口 (我们不需要)
  • 关注与取消接口
  • 他人信息接口

显然,这样业务耦合了,并且他人主页中出现了我们不需要使用的列表接口!

通过类的继承,明显无法满足每一个接口都独立并且解耦,因为Swift是单继承关系

换个角度

既然class的类继承不行,我们可以试试使用protocol。

protocol可以多继承,而且protocol可以被多个类遵循,这样的话,我只需要将每个一个接口都通过protocol来定义与实现。

于是我先定义了一个空协议BaseRequestable,然后每个网络请求都定义一个协议,并且继承BaseRequestable协议,并在extension中进行实现:

swift 复制代码
/// 基类协议,让其他业务请求都继承这个协议,如此一来,万一需要as?进行转换留余地
protocol BaseRequestable {}

/// 列表接口
protocol ListRequest: BaseRequestable {
    func requestList() -> Single<Moya.Response>
}

extension ListRequest {
    func requestList() -> Single<Moya.Response> {
        homeProvider.rx.request(HomeService.list)
    }
}

/// 他人主页接口
protocol OtherInfoRequest: BaseRequestable {
    func requestOtherInfo() -> Single<Moya.Response>
}

extension OtherInfoRequest {
    func requestOtherInfo() -> Single<Moya.Response> {
        homeProvider.rx.request(HomeService.otherInfo)
    }
}

/// 关注与取消接口
protocol AttentionRequest: BaseRequestable {
    func requestAction(type:ActionType) -> Single<Moya.Response>
}

extension AttentionRequest {
    func requestAction(type:ActionType) -> Single<Moya.Response> {
        homeProvider.rx.request(HomeService.attention(type))
    }
}

而后不同ViewModel直接将不同的Request当作最小工件装配即可:

swift 复制代码
class 关注列表ViewModel: ListRequest, AttentionRequest{
    
}

class 他人主页ViewModel: OtherInfoRequest, AttentionRequest {
    
}

有没有其他的方式?

上面这种思路是将每一个接口都当作一个独立的protocol去实现,虽然解耦的很不错,但是这样写起来有点费手,而且如果一个ViewModel中有5个甚至更多的接口请求,那么就会变成这样:

swift 复制代码
class ViewModel: Request1, Request2, Request3, Request4, Request5... {
    
}

如果熟悉前端或者Retrofit自动化生成,你会发现它们会把所有的接口集中放在一起维护:

swift 复制代码
protocol RequestProtocol {
    static func requestList() -> Single<Moya.Response>
    
    static func requestOtherInfo() -> Single<Moya.Response>

    static func requestAction(type:ActionType) -> Single<Moya.Response>
}

extension RequestProtocol {
    static func requestList() -> Single<Moya.Response> {
        homeProvider.rx.request(HomeService.list)
    }
    
    static func requestOtherInfo() -> Single<Moya.Response> {
        homeProvider.rx.request(HomeService.otherInfo)
    }

    static func requestAction(type:ActionType) -> Single<Moya.Response> {
        homeProvider.rx.request(HomeService.attention(type))
    }
}

enum Request: RequestProtocol {}

不同的ViewModel,根据需要调用这个Request的方法即可:

swift 复制代码
class 关注列表ViewModel {
    func getList() {
        Request.requestList()
    }
}

class 他人主页ViewModel {
    func getOtherInfo() {
        Request.requestOtherInfo()
    }
}

这样的好处是所有的接口都集中管理在一个protocol中,减少每个接口一个protocol的维护量,过于分散的问题。

思考与总结

在Request中是否需要进行数据转换?

我理解,网络请求就是一个单一的功能,返回数据即可,而涉及的转换,判断都不应该在这一层进行处理,所以最后返回的结果就是Single<Moya.Response>或者Moya.Response即可。

Moya与App之间到底应该如何分层?

这个是Moya官方给出的示例图,Moya封装了Alamofire的细节之后,App其实就可以直接调用了:

swift 复制代码
import Moya

enum HomeService {

}

extension HomeService: TargetType {

}

let homeProvider = MoyaProvider<HomeService>(plugins: plugins)

homeProvider其实不管在任何你想要调用的位置都可以使用。

只是,在目前流行的MVVM中,更倾向于将homeProvider在ViewModel中调用罢了,这里我们不过是将ViewModel层中的调用做了更加精细化的处理,这样做的好处是:

  1. 可以将网络请求与ViewModel进行解耦
  2. 可以将网络请求进行复用
  3. 可以将网络请求进行组合
  4. 可以将网络请求进行分层
  5. 可以将网络请求进行单元测试
  6. 可以将网络请求进行Mock

如果去查阅GetX在Flutter中的使用,你会发现,Page与Controller的关系亦是如此,Page只关心页面的构建,所有的逻辑都是Controller中,而在Controller中又将网络请求独立处理,当然这是一个题外话了,我们有空再聊。

相关推荐
VeryCool4 分钟前
React Native新架构升级实战【从 0.62 到 0.72】
前端·javascript·架构
键盘敲没电1 小时前
【iOS】Blocks学习
学习·ios·性能优化·objective-c·cocoa
学前端搞口饭吃1 小时前
uniapp打ios包
ios·uni-app
```陪伴1 小时前
uniapp打包IOS私钥证书过期了,如何在非mac系统操作
macos·ios·uni-app
七月丶2 小时前
2025 年主流混合开发框架全面对比:React Native、Flutter、Weex 谁更能打?
前端·后端·架构
何双新3 小时前
企业AI应用模式解析:从本地部署到混合架构
人工智能·架构
Blossom.1183 小时前
量子计算在金融领域的应用与展望
数据库·人工智能·分布式·金融·架构·量子计算·ai集成
WDeLiang4 小时前
学习笔记: Mach-O 文件
学习·ios
Goboy4 小时前
SQL面试实战,30分钟征服美女面试官
后端·面试·架构