Swift-Moya 源码解析

本文详细解析了 Swift 中的网络库 Moya,从定义、使用到各个核心组件如 MoyaProvider、Endpoint、TargetType、Plugins 等的解析,探讨了如何通过 Moya 进行网络请求、自定义行为以及插件机制,帮助理解 Moya 的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.Moya的定义

  • Moya是一个高度抽象的网络库,他的理念是让你不用关心网络请求的底层的实现细节,只用定义你关心的业务。且Moya采用桥接和组合来进行封装(默认桥接了Alamofire),使得Moya非常好扩展,让你不用修改Moya源码就可以轻易定制。官方给出几个Moya主要优点:
    • 编译时检查API endpoint权限
    • 让你使用枚举定义各种不同Target, endpoints
    • stubs当做一等公民对待,因此测试超级简单。

2.Moya的使用

  • Moya的使用分成几步,首先需要先自定义一个枚举类型。
enum SHChannelViewModelApiManager{
    case getChannelList(Bool)
    case getItemList(String)

}
  • 然后遵循开闭原则,让枚举的分类遵循MoyaTargetType,按需实现定义的各种get方法
public protocol TargetType {

    /// The target's base `URL`.
    var baseURL: URL { get }

    /// The path to be appended to `baseURL` to form the full `URL`.
    var path: String { get }

    /// The HTTP method used in the request.
    var method: Moya.Method { get }

    /// Provides stub data for use in testing.
    var sampleData: Data { get }

    /// The type of HTTP task to be performed.
    var task: Task { get }

    /// A Boolean value determining whether the embedded target performs Alamofire validation. Defaults to `false`.
    var validate: Bool { get }

    /// The headers to be used in the request.
    var headers: [String: String]? { get }
}
extension  SHChannelViewModelApiManager:TargetType {
   var baseURL: URL {
        return URL(string: baseUrl)!
    }
    var task: Task {
        switch self {
        case .getChannelList:
            return .requestPlain
        case .getItemList(let pipe):
            return .requestParameters(parameters: ["pipe":pipe], encoding: URLEncoding.queryString)
        }
    }
    var method: Moya.Method {
        return .get
    }
    var path: String {
        switch self {
        case .getChannelList(let isToday):
            if isToday{
               return "/Youmeng/chaxunservletall"
            }else{
              return "/Youmeng/chaxunservletallhistory"
            }
        case .getItemList:
            return itemListUrl

        }

    }
}
  • 最后创建MoyaProvider对象,泛型允许传入任何你定义的遵循TargetType协议的枚举,
    let provider = MoyaProvider<SHChannelViewModelApiManager>()

  • 使用MoyaProvider对象发起请求
    provider.rx.request(.getItemList(pipe)).mapArr([SHChannelItemTopModel].self).subscribe(onSuccess: { [weak self](model) in
        self?.topModels = model
        self?.itemOutput.onNext(true)
        }) { [weak self](error) in
            self?.itemOutput.onNext(false)
            }.disposed(by: bag)
    }

3.Moya的所有文件解析

  • Provider

  • TargetType

    • TargetType

    • MultiTarget (MultiTarget用于使MoyaProvider能够处理多个TargetType

  • Result

    • Response

    • MoyaError (是一个枚举,定义了 Moya可能抛出的各种错误,包括上面说的 Response三个map方法出错,状态码出错,解码出错,和参数编码错误等,同时有两个get方法,得出错误的Response返回以及错误描述返回)

  • Plugins

  • Alamofire
    这里有一个iOS交流圈:891 488 181 分享BAT,阿里面试题、面试经验,讨论技术, 感兴趣的话大家一起交流学习!

    • Moya+Alamofire (MoyaAlamofire的桥接文件,桥接模式保证了最少知道原则,如果进行替换Alamofire,主要修改这个文件)
    • MultipartFormData (多文件上传与Alamofire的桥接,通过 append等方法把moya形式的MultipartFormData添加到Alamofire里去)
  • URL

    • URL+Moya(通过获取TargetTypebaseURLpath初始化一个URL)

    • URLRequest+Encoding(对URLRequest的两个encoded方法)

3.1.MoyaProvider
MoyaProvider 初始化

MoyaProvider是请求提供者类。只能通过该类发起请求,类的初始化如下

    public init(endpointClosure: @escaping EndpointClosure = MoyaProvider.defaultEndpointMapping,
                requestClosure: @escaping RequestClosure = MoyaProvider.defaultRequestMapping,
                stubClosure: @escaping StubClosure = MoyaProvider.neverStub,
                callbackQueue: DispatchQueue? = nil,
                manager: Manager = MoyaProvider<Target>.defaultAlamofireManager(),
                plugins: [PluginType] = [],
                trackInflights: Bool = false) {

        self.endpointClosure = endpointClosure
        self.requestClosure = requestClosure
        self.stubClosure = stubClosure
        self.manager = manager
        self.plugins = plugins
        self.trackInflights = trackInflights
        self.callbackQueue = callbackQueue
    }

由以上代码可以得知,初始化可传入的参数。

  • EndpointClosure是一个把传入的Target转化为Endpoint对象的闭包,

        public typealias EndpointClosure = (Target) -> Endpoint<Target>
    
    

    既然如此

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值