iOS 坑的集中营

Swift-Moya 源码解析

2020-12-03  本文已影响0人  iOS_磊

1.Moya的定义

2.Moya的使用

enum SHChannelViewModelApiManager{
    case getChannelList(Bool)
    case getItemList(String)

}
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

        }

    }
}
    let provider = MoyaProvider<SHChannelViewModelApiManager>()

    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的所有文件解析

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
    }

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

MoyaProvider 发送请求

3.2.MoyaProvider+Defaults

MoyaProvider+Defaults里面就是 3 个默认方法,前面已经提到过,就不多做赘述了

3.3.MoyaProvider+Internal

 private func performRequest(_ target: Target, request: URLRequest, callbackQueue: DispatchQueue?, progress: Moya.ProgressBlock?, completion: @escaping Moya.Completion, endpoint: Endpoint<Target>, stubBehavior: Moya.StubBehavior) -> Cancellable {
        switch stubBehavior {
        case .never:
            switch endpoint.task {
            case .requestPlain, .requestData, .requestJSONEncodable, .requestParameters, .requestCompositeData, .requestCompositeParameters:
                return self.sendRequest(target, request: request, callbackQueue: callbackQueue, progress: progress, completion: completion)
            case .uploadFile(let file):
                return self.sendUploadFile(target, request: request, callbackQueue: callbackQueue, file: file, progress: progress, completion: completion)
            case .uploadMultipart(let multipartBody), .uploadCompositeMultipart(let multipartBody, _):
                guard !multipartBody.isEmpty && endpoint.method.supportsMultipart else {
                    fatalError("\(target) is not a multipart upload target.")
                }
                return self.sendUploadMultipart(target, request: request, callbackQueue: callbackQueue, multipartBody: multipartBody, progress: progress, completion: completion)
            case .downloadDestination(let destination), .downloadParameters(_, _, let destination):
                return self.sendDownloadRequest(target, request: request, callbackQueue: callbackQueue, destination: destination, progress: progress, completion: completion)
            }
        default:
            return self.stubRequest(target, request: request, callbackQueue: callbackQueue, completion: completion, endpoint: endpoint, stubBehavior: stubBehavior)
        }
    }

3.4.Endpoint

3.5.TargetType

TargetType就是用于定义MoyaProvider的协议,自定义枚举需要签订的协议

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 }
}

3.6.Response

Response就是对对MoyaProvider.request的响应

3.7.Plugin

Moya Plugin接收回调(调用时机都是在MoyaProvider+Internal里),以在发送或接收请求时执行。例如,一个插件可以用于

1.记录网络请求

2.隐藏和显示网络活动指示器

3.在请求中注入附加信息

3.8.AccessTokenPlugin

AccessTokenPlugin可用于做JWTBearer 认证 和 Basic 认证,也可以做OAuth认证,不过比较麻烦

3.9.CredentialsPlugin

AccessTokenPlugin是做 HTTP 身份验证的,在 willSend里验证


  public func willSend(_ request: RequestType, target: TargetType) {
  //credentialsClosure返回一个 URLCredential对象,用于身份验证的系统 api
      if let credentials = credentialsClosure(target) {
      //通过Moya+Alamofire的“extension Request: RequestType { }” 可知,这个authenticate方法最后还是调用的 Alamofire的的认证方法
          _ = request.authenticate(usingCredential: credentials)
      }
  }

3.10.NetworkActivityPlugin

NetworkActivityPlugin还是比较简单的,就是单纯的抽离willSenddidReceive转变成NetworkActivityChangeTypebeganended,可以添加菊花的显示和隐藏

    public func willSend(_ request: RequestType, target: TargetType) {
      networkActivityClosure(.began, target)
  }

  /// Called by the provider as soon as a response arrives, even if the request is canceled.
  public func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType) {
      networkActivityClosure(.ended, target)
  }

3.11.NetworkLoggerPlugin

NetworkLoggerPlugin是网络日志的打印,还是在willSenddidReceive打印了网络状态

    public func willSend(_ request: RequestType, target: TargetType) {
     if let request = request as? CustomDebugStringConvertible, cURL {
         output(separator, terminator, request.debugDescription)
         return
     }
     outputItems(logNetworkRequest(request.request as URLRequest?))
 }

 public func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType) {
     if case .success(let response) = result {
         outputItems(logNetworkResponse(response.response, data: response.data, target: target))
     } else {
         outputItems(logNetworkResponse(nil, data: nil, target: target))
     }
 }

作者:Mikebanana
链接:https://juejin.cn/post/6899362830114357256

上一篇 下一篇

猜你喜欢

热点阅读