The definition of 1. Moya

  • MoyaIs a highly abstract network library, the idea is that you don’t have to worry about the low-level implementation details of network requests, just define the business you care about. andMoyaUse bridging and composition for encapsulation (bridging by defaultAlamofire),MoyaIt’s very extensible and you don’t have to modify itMoyaThe source code can be easily customized. The official list is how manyMoyaMain advantages:
    • Compile time checkAPI endpointpermissions
    • Let you define various differences using enumerationsTarget.endpoints
    • thestubsTreat them like first-class citizens, so the test is super easy.

2. Moya’s use

  • MoyaThe use of an enumeration type is divided into several steps, starting with a custom enumeration type.
enum SHChannelViewModelApiManager{
    case getChannelList(Bool)
    case getItemList(String)
    
}
Copy the code
  • Then follow the open close principle and let the classification of enumerations followMoyatheTargetType, as defined by the implementation on demandgetmethods
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 }
}
Copy the code
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
           
        }
        
    }
}
Copy the code
  • Finally createMoyaProviderObject generics allow you to pass in whatever you define to followTargetTypeEnumeration of protocols,
    let provider = MoyaProvider<SHChannelViewModelApiManager>()

Copy the code
  • useMoyaProviderObject initiates a request
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) }Copy the code

3. All file parsing of Moya

  • Provider

    • MoyaProvider

    • MoyaProvider+Defaults

    • MoyaProvider+Internal

    • Endpoint

    • Task (is an enumeration that defines the form of the Task, whether it is passed or not, whether it is uploaded or downloaded)

    • Cancellable (simply indicates whether the request can be cancelled, and a method to cancel the request)

  • TargetType

    • TargetType

    • MultiTarget (used to enable MoyaProvider to handle multiple targetTypes)

  • Result

    • Response

    • MoyaError (is an enumeration that defines all kinds of errors that Moya can throw, including the above mentioned three map methods error, status code error, decoding error, parameter encoding error, etc., and two get methods to return the error Response and error description return)

  • Plugins

    • Plugin

    • AccessTokenPlugin

    • NetworkActivityPlugin

    • NetworkLoggerPlugin

  • Alamofire

    • Moya+Alamofire (MoyaandAlamofireOf the bridge files, the bridge mode guarantees the least known principle if replacement is madeAlamofire, mainly modify this file)
    • MultipartFormData (multifile upload withAlamofireBridge, throughappendMethods such as themoyaIn the form ofMultipartFormDataAdded to theAlamofireTo)
  • URL

    • URL+Moya(initialize a URL by getting the baseURL and path of TargetType)

    • URLRequest+Encoding(two encoded methods for URLRequest)

3.1. MoyaProvider

MoyaProvider initialization

MoyaProvider is the request provider class. Requests can only be made through this class, which is initialized as follows

    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
    }
Copy the code

As you can see from the above code, initialization can pass in parameters.

  • EndpointClosure is a closure that converts the passed Target into an Endpoint object,

        public typealias EndpointClosure = (Target) -> Endpoint<Target>
    
    Copy the code

    In that case, let’s take a quick look at what’s inside the Endpoint object

    Open Class Endpoint<Target> {public TypeAlias SampleResponseClosure = () -> EndpointSampleResponse Specifies the requested URL Let URL: String /// Stub data response(test) open let sampleResponseClosure: SampleResponseClosure // Open let method: Moya. Open let httpHeaderFields: [String: String]? public init(url: String, sampleResponseClosure: @escaping SampleResponseClosure, method: Moya.Method, task: Task, httpHeaderFields: [String: String]?) { self.url = url self.sampleResponseClosure = sampleResponseClosure self.method = method self.task = task self.httpHeaderFields = httpHeaderFields } ... }Copy the code

    The EndpointClosure function allows you to re-customize network requests based on business requirements and test data using stubs. Take a look at the official default closure implementation

     public final class func defaultEndpointMapping(for target: Target) -> Endpoint<Target> {
         return Endpoint(
             url: URL(target: target).absoluteString,
             sampleResponseClosure: { .networkResponse(200, target.sampleData) },
             method: target.method,
             task: target.task,
             httpHeaderFields: target.headers
         )
     }
    Copy the code
  • The RequestClosure implementation converts the Endpoint to the actual request object URLRequest

    //RequestClosure public typealias RequestClosure = (Endpoint<Target>, @escaping RequestResultClosure) -> Void // Above RequestResultClosure Public TypeAlias RequestResultClosure = (Result<URLRequest, MoyaError>) -> VoidCopy the code

    Take a look at the default implementation provided by Moya

    public final class func defaultRequestMapping(for endpoint: Endpoint<Target>, closure: RequestResultClosure) {do {//urlRequest let urlRequest = try endpoint.urlRequest() (.success(urlRequest)) // Closure (.success(urlRequest)) {//urlRequest request let urlRequest = try endpoint.urlRequest()) // Error of type MoyaError, } catch moyaerror.requestMapping (let URL) {closure(.failure(moyaerror.requestmapping (url)))} catch MoyaError.parameterEncoding(let error) { closure(.failure(MoyaError.parameterEncoding(error))) } catch { closure(.failure(MoyaError.underlying(error, nil))) } }Copy the code

    This code gets urlRequest via endpoint.urlRequest(), so let’s look at the implementation of urlRequest()

    public func urlRequest() throws -> URLRequest { guard let requestURL = Foundation.URL(string: url) else { throw MoyaError.requestMapping(url) } var request = URLRequest(url: requestURL) request.httpMethod = method.rawValue request.allHTTPHeaderFields = httpHeaderFields switch task { case .requestPlain, .uploadFile, .uploadMultipart, .downloadDestination: return request case .requestData(let data): request.httpBody = data return request //................. A little code omitted here}}Copy the code

    Now it’s clear that it did turn into URLRequest. In fact, this is Moya’s last chance for you, for example, if you want to set a timeout,

    let requestClosure = { (endpoint:Endpoint<SHChannelViewModelApiManager>,closure:RequestResultClosure){ do { var UrlRequest = try endpoint.urlRequest() // Set timeout, UrlRequest configurable items can be in this configuration urlRequest timeoutInterval = 60 closure (. Success (urlRequest)} the catch MoyaError.requestMapping(let url) { closure(.failure(MoyaError.requestMapping(url))) } catch MoyaError.parameterEncoding(let error) { closure(.failure(MoyaError.parameterEncoding(error))) } catch { closure(.failure(MoyaError.underlying(error, nil))) } } }Copy the code
  • StubClosure returns an enumeration of StubBehaviors that lets you tell Moya whether or how to use stubs to return data. The default is none

     public typealias StubClosure = (Target) -> Moya.StubBehavior
    
    Copy the code
    Public enum StubBehavior {/// Data returned without Stub case Never /// Data returned with Stub case immediate /// Data returned with Stub after a period of time Case delayed(seconds: TimeInterval) }Copy the code

    Here’s an example to summarize the use of these three closures

    var sampleData: Data { return "{'code': 0,'Token':'3764837egfdg8dfg8e93hr93'}".data(using: String.Encoding.utf8)! } / / defined in SHChannelViewModelApiManager let outside endPointAction = {(target: SHChannelViewModelApiManager) -> Endpoint<SHChannelViewModelApiManager> in return Endpoint( url: URL(target: target).absoluteString, sampleResponseClosure: { .networkResponse(400, target.sampleData) }, method: Target. Method, task: target. Task, httpHeaderFields: target.headers)} SHChannelViewModelApiManager) -> Moya.StubBehavior = { type in return Moya.StubBehavior.delayed(seconds: 3)} / / create moyaProvider let moyaProvider = moyaProvider < SHChannelViewModelApiManager > (endpointClosure: EndPointAction stubClosure: stubAction) / / use moyaProvider. Request (SHChannelViewModelApiManager. GetChannelList)......Copy the code
  • Manager is nothing to say, is Alamofire SessionManager

    public typealias Manager = Alamofire.SessionManager
    
    Copy the code

    Manager is the real class for network requests. Moya does not provide the Manager class itself. Moya simply Bridges other network request classes (bridge mode). This is done so that callers can easily customize and replace the library of network requests. If you don’t want to use Alamofire, you can simply switch to another library,

  • CallbackQueue is passed to Alamofire as a callbackQueue, if nil – Alamofire’s default will be used. Here is an example of the use found

        if let callbackQueue = callbackQueue {
                  callbackQueue.async(execute: sendProgress)
              } else {
                  sendProgress()
              }
    Copy the code
  • Plugins-moya provides a plug-in mechanism that allows us to build our own plug-in classes to do additional things. For example, write Log, display “chrysanthemum” and so on. The purpose of pulling out the Plugin layer is to keep the Provider accountable and open and closed. Disconnect from behaviors that don’t relate to your network. Avoiding all sorts of business clumping together is bad for scaling (more like the lifecycle of a request, called at the insertion point)

  • TrackInflights, according to the code logic can be seen, this is whether to handle repeated requests. One explanation is whether to track repeated network requests.

    If trackInflights {objc_sync_enter(self)// Recursive lock var inflightCompletionBlocks = self.inflightrequests [endpoint] inflightCompletionBlocks? .append(pluginsWithCompletion) self.inflightRequests[endpoint] = inflightCompletionBlocks objc_sync_exit(self) if inflightCompletionBlocks ! = nil {// If it exists, Return cancellableToken} else {objc_sync_enter(self) // If there is no value where key is an endpoint, Initializing a self.inflightrequests [endpoint] = [pluginsWithCompletion] objc_sync_exit(self)}}Copy the code

    A request with trackInflights set to true when init will store the endpoint of the request in Moya. When the data is returned, if a duplicate request needs to be traced, the data returned by the request is actually sent once and returned multiple times.

MoyaProvider sends requests
  • The request method in Moya is a unified request entry. Only need to configure the required parameters in the method, including the need to generate the request address, request parameters through enumeration type, very clear classification and management. Use the. Syntax to generate the corresponding enumeration, and then generate the endpoint, URLRequest, and so on

        @discardableResult
      open func request(_ target: Target,
                        callbackQueue: DispatchQueue? = .none,
                        progress: ProgressBlock? = .none,
                        completion: @escaping Completion) -> Cancellable {
    
          let callbackQueue = callbackQueue ?? self.callbackQueue
          return requestNormal(target, callbackQueue: callbackQueue, progress: progress, completion: completion)
      }
    Copy the code
  • Target is the custom enumeration passed in.

  • CallbackQueue ditto

  • Progress represents a callback to request the completion progress of the task. It is not used by default

    public typealias ProgressBlock = (_ progress: ProgressResponse) -> Void
    
    Copy the code

    So let’s go back to ProgressResponse

    public struct ProgressResponse { /// The optional response of the request. public let response: Response? /// An object that conveys ongoing progress for a given request. public let progressObject: Progress? /// Initializes a `ProgressResponse`. public init(progress: Progress? = nil, response: Response? = nil) { self.progressObject = progress self.response = response } /// The fraction of the overall work completed by the  progress object. public var progress: Double { return progressObject? .fractionCompleted?? 1.0} /// A Boolean value whether the request is completed. Public var completed: Bool {return progress == 1.0&&response! = nil } }Copy the code

    ProgressObject is a Progress object from the Foundation framework. It is a class added to iOS 7 specifically for monitoring the Progress of tasks

  • Completion is the callback that is returned after the request is completed

    public typealias Completion = (_ result: Result<Moya.Response, MoyaError>) -> Void
    Copy the code

3.2. MoyaProvider + Defaults

There are three default methods in MoyaProvider+Defaults

  • defaultEndpointMappingreturnEndpointDefault method of
  • defaultRequestMappingThe essence is to returnURLRequestDefault method of
  • defaultAlamofireManagerReturn to the network librarymanagerDefault method (default is Alamofire)

3.3. MoyaProvider + Internal

  • MethodIs theAlamofire.HTTPMethodExtension, addsupportsMultipartMethod to determine whether multiple request modes are supported together
    extension Method { /// A Boolean value determining whether the request supports multipart. public var supportsMultipart:  Bool { switch self { case .post, .put, .patch, .connect: return true case .get, .delete, .head, .options, .trace: return false } } }Copy the code
  • requestNormalisMoyaProviderIn therequestThe method of tuning, it says in the method,MoyaWhat exactly was done at the time of the request
    func requestNormal(_ target: Target, callbackQueue: DispatchQueue? , progress: Moya.ProgressBlock? , completion: @escaping Moya.Completion) -> Cancellable {// Get the endpoint, stubBehavior, and initialize cancellableToken let endpoint = Self. endpoint(target) let stubBehavior = self.stubClosure(target) // This class controls whether to cancel the request task let cancellableToken = CancellableWrapper() // Allow plugins to modify response let pluginsWithCompletion: Moya.Completion = { result in let processedResult = self.plugins.reduce(result) { $1.process($0, target: Target)} completion(processedResult)} if trackInflights {objc_sync_Enter (self)// Recursive lock var inflightCompletionBlocks = self.inflightRequests[endpoint] inflightCompletionBlocks? .append(pluginsWithCompletion) self.inflightRequests[endpoint] = inflightCompletionBlocks objc_sync_exit(self) if inflightCompletionBlocks ! = nil {// If it exists, Return cancellableToken} else {objc_sync_enter(self) // If there is no value where key is an endpoint, Initializing self.inflightrequests [endpoint] = [pluginsWithCompletion] objc_sync_exit(self)}} Let performNetworking = {(requestResult: Result<URLRequest, MoyaError>) in // Is return the wrong type for the cancel the error data of the if cancellableToken. IsCancelled {self. CancelCompletion (pluginsWithCompletion, target: target) return } var request: URLRequest! switch requestResult { case .success(let urlRequest): request = urlRequest case .failure(let error): Request let preparedRequest = self.plugins.reduce(request) {pluginsWithCompletion(.failure(error)) return} $1. Prepare ($0, target: target)} // Define a closure that maps the data to Result let networkCompletion: Moya.Completion = { result in if self.trackInflights { self.inflightRequests[endpoint]? .forEach { $0(result) } objc_sync_enter(self) self.inflightRequests.removeValue(forKey: PluginsWithCompletion (result)}} This step is the next step in executing the request. Will continue to pass all the parameters cancellableToken. InnerCancellable = self. PerformRequest (target, request: preparedRequest, callbackQueue: callbackQueue, progress: progress, completion: networkCompletion, endpoint: endpoint, stubBehavior: } // The next step is to use the two closures defined above, RequestClosure (endpoint, performNetworking) return cancellableToken}Copy the code
  • performRequestIs the next step in executing the request above, the internal implementation of this method, according toswitch stubBehaviorendpoint.taskTo perform the corresponding request mode separately.
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) } }Copy the code

3.4. The Endpoint

  • EndpointThe initialization method of
     public init(url: String,
                 sampleResponseClosure: @escaping SampleResponseClosure,
                 method: Moya.Method,
                 task: Task,
                 httpHeaderFields: [String: String]?) {
    
         self.url = url
         self.sampleResponseClosure = sampleResponseClosure
         self.method = method
         self.task = task
         self.httpHeaderFields = httpHeaderFields
    Copy the code
  • addingUse to create a new oneEndpointIs a convenience method that has the same properties as the recipient, but adds an HTTP request header.
    open func adding(newHTTPHeaderFields: [String: String]) -> Endpoint<Target> {
         return Endpoint(url: url, sampleResponseClosure: sampleResponseClosure, method: method, task: task, httpHeaderFields: add(httpHeaderFields: newHTTPHeaderFields))
     }
    
    Copy the code
  • replacingThe method is the same, but changedTask
  • urlRequest()Methods conversionEndpointintoURLRequest

3.5. TargetType

TargetType is the protocol used to define the MoyaProvider. Custom enumerations need to be signed

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 }
}
Copy the code

3.6. The Response

A Response is a Response to MoyaProvider. Request

  • ResponseThe initialization
    public init(statusCode: Int, data: Data, request: URLRequest? = nil, response: HTTPURLResponse? = nil) {self.statuscode = statusCode // statusCode self.data = data // binary data returned self.request = request // URL request self.response = Response // HTTP response}Copy the code

    In addition, there is a built-inmapJSONandmapStringIs used todataintoJSONOr a string,map<D: Decodable>With the model, you can convert data to signDecodableClass object,mapImageOn his return todataData is used when a picture binary data is returned directly into a picture object

    func mapImage() throws -> Image { guard let image = Image(data: data) else { throw MoyaError.imageMapping(self) } return image } func mapJSON(failsOnEmptyData: Bool = true) throws -> Any { do { return try JSONSerialization.jsonObject(with: data, options: .allowFragments) } catch { if data.count < 1 && ! failsOnEmptyData { return NSNull() } throw MoyaError.jsonMapping(self) } } public func mapString(atKeyPath keyPath: String? = nil) throws -> String { if let keyPath = keyPath { // Key path was provided, try to parse string at key path guard let jsonDictionary = try mapJSON() as? NSDictionary, let string = jsonDictionary.value(forKeyPath: keyPath) as? String else { throw MoyaError.stringMapping(self) } return string } else { // Key path was not provided, parse entire response as string guard let string = String(data: data, encoding: .utf8) else { throw MoyaError.stringMapping(self) } return string } } func map<D: Decodable>(_ type: D.Type, atKeyPath keyPath: String? = nil, using decoder: JSONDecoder = JSONDecoder()) throws -> D { let serializeToData: (Any) throws -> Data? = { (jsonObject) in guard JSONSerialization.isValidJSONObject(jsonObject) else { return nil } do { return try JSONSerialization.data(withJSONObject: jsonObject) } catch { throw MoyaError.jsonMapping(self) } } let jsonData: Data if let keyPath = keyPath { guard let jsonObject = (try mapJSON() as? NSDictionary)? .value(forKeyPath: keyPath) else { throw MoyaError.jsonMapping(self) } if let data = try serializeToData(jsonObject) { jsonData = data } else { let wrappedJsonObject = ["value": jsonObject] let wrappedJsonData: Data if let data = try serializeToData(wrappedJsonObject) { wrappedJsonData = data } else { throw MoyaError.jsonMapping(self) } do { return try decoder.decode(DecodableWrapper<D>.self, from: wrappedJsonData).value } catch let error { throw MoyaError.objectMapping(error, self) } } } else { jsonData = data } do { return try decoder.decode(D.self, from: jsonData) } catch let error { throw MoyaError.objectMapping(error, self) } }Copy the code

3.7. The Plugin

The Moya Plugin receives callbacks (all within MoyaProvider+Internal) to be executed when a request is sent or received. For example, a plug-in can be used for

1. Log network requests 2. Hide and display network activity indicators 3Copy the code

  • Prepare can be used to modify the request before it is sent. (Before stub test)

        func prepare(_ request: URLRequest, target: TargetType) -> URLRequest
    
    Copy the code
  • WillSend is called before a network request is sent (after a stub test)

        func willSend(_ request: RequestType, target: TargetType)
    
    Copy the code
  • DidReceive is called after receiving the response, but before MoyaProvider calls its completion handler.

        func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType)
    
    Copy the code
  • Process is called before Completion to modify the result

        func process(_ result: Result<Moya.Response, MoyaError>, target: TargetType) -> Result<Moya.Response, MoyaError>
    
    Copy the code
  • RequestType is the parameter that willSend needs to pass in. It is designed to follow Demeter’s rule (least known), and we use this protocol instead of Alamofire requests to avoid giving away this abstraction. Plugin should be completely unaware of Alamofire

    public protocol RequestType {
    
      /// Retrieve an `NSURLRequest` representation.
      var request: URLRequest? { get }
    
      /// Authenticates the request with a username and password.
      func authenticate(user: String, password: String, persistence: URLCredential.Persistence) -> Self
    
      /// Authenticates the request with an `NSURLCredential` instance.
      func authenticate(usingCredential credential: URLCredential) -> Self
     }
    
    Copy the code

3.8. AccessTokenPlugin

AccessTokenPlugin can be used for Bearer and Basic authentication of JWT as well as OAuth authentication, but it is more difficult

  • Pass when necessaryprepareAdd authorization request headers to verify
    public func prepare(_ request: URLRequest, target: TargetType) -> URLRequest { guard let authorizable = target as? AccessTokenAuthorizable else { return request } let authorizationType = authorizable.authorizationType var request = request switch authorizationType { case .basic, .bearer: // Add Authorization, TokenClosure returns a head can apply request access token let authValue = authorizationType. RawValue + "" + tokenClosure () request.addValue(authValue, forHTTPHeaderField: "Authorization") case .none: break } return request }Copy the code

3.9. CredentialsPlugin

AccessTokenPlugin does HTTP authentication in willSend

public func willSend(_ request: RequestType, target: TargetType) {//credentialsClosure returns an URLCredential object, If let credentials = credentialsClosure(target) {// Through Moya+Alamofire "Extension Request: RequestType {} "Authenticate (usingCredential: credentials)}}Copy the code

3.10.Net workActivityPlugin

NetworkActivityPlugin is relatively simple, it is a simple willSend and didReceive into NetworkActivityChangeType began and ended, can add the chrysanthemum show and hide

    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)
  }
Copy the code

3.11.Net workLoggerPlugin

NetworkLoggerPlugin prints network logs or network state in willSend and didReceive

    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))
     }
 }
Copy the code