1、初始化MoyaProvider
初始化:
/// Initializes a provider.
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: @escaping EndpointClosure = MoyaProvider.defaultEndpointMapping,
requestClosure: @escaping RequestClosure = MoyaProvider.defaultRequestMapping,
stubClosure: @escaping StubClosure = MoyaProvider.neverStub,
manager: Manager = MoyaProvider<Target>.defaultAlamofireManager(),
plugins: [PluginType] = [],
trackInflights: Bool = false
endpointClosure:是target转成Endpoint类型
requestClosure:是将Endpoint转成URLRequest,用block进行处理
stubClosure:测试用
plugins:插件,网络请求有关信息以插件形式告诉外界
manager:会话管理者
callbackQueue:回调过来的queue
2、调用request
/// Designated request-making method. Returns a `Cancellable` token to cancel the request later.
@discardableResult
open func request(_ target: Target,
callbackQueue: DispatchQueue? = .none,
progress: ProgressBlock? = .none,
completion: @escaping Completion) -> Cancellable {
//第2步:调用request
let callbackQueue = callbackQueue ?? self.callbackQueue
return requestNormal(target, callbackQueue: callbackQueue, progress: progress, completion: completion)
}
/// Performs normal requests.
func requestNormal(_ target: Target, callbackQueue: DispatchQueue?, progress: Moya.ProgressBlock?, completion: @escaping Moya.Completion) -> Cancellable {
//将target转成Endpoint,MoyaProvider.defaultEndpointMapping执行这个方法
let endpoint = self.endpoint(target)
let stubBehavior = self.stubClosure(target)
let cancellableToken = CancellableWrapper()
// Allow plugins to modify response
let pluginsWithCompletion: Moya.Completion = { result in
// /// Called to modify a result before completion. 在完成前修改结果
let processedResult = self.plugins.reduce(result) { $1.process($0, target: target) }
completion(processedResult)
}
if trackInflights {
objc_sync_enter(self)
var inflightCompletionBlocks = self.inflightRequests[endpoint]
inflightCompletionBlocks?.append(pluginsWithCompletion)
self.inflightRequests[endpoint] = inflightCompletionBlocks
objc_sync_exit(self)
if inflightCompletionBlocks != nil {
return cancellableToken
} else {
objc_sync_enter(self)
self.inflightRequests[endpoint] = [pluginsWithCompletion]
objc_sync_exit(self)
}
}
//进行请求前一步处理
let performNetworking = { (requestResult: Result<URLRequest, MoyaError>) in
if cancellableToken.isCancelled {
self.cancelCompletion(pluginsWithCompletion, target: target)
return
}
var request: URLRequest!
switch requestResult {
case .success(let urlRequest):
request = urlRequest
case .failure(let error):
pluginsWithCompletion(.failure(error))
return
}
// Allow plugins to modify request
let preparedRequest = self.plugins.reduce(request) { $1.prepare($0, target: target) }
//网络请求处理及进度回调
let networkCompletion: Moya.Completion = { result in
if self.trackInflights {
self.inflightRequests[endpoint]?.forEach { $0(result) }
objc_sync_enter(self)
self.inflightRequests.removeValue(forKey: endpoint)
objc_sync_exit(self)
} else {
pluginsWithCompletion(result)
}
}
//请求
cancellableToken.innerCancellable = self.performRequest(target, request: preparedRequest, callbackQueue: callbackQueue, progress: progress, completion: networkCompletion, endpoint: endpoint, stubBehavior: stubBehavior)
}
//执行初始化传过来的,MoyaProvider.defaultRequestMapping方法,进一步做URLquest请求处理
requestClosure(endpoint, performNetworking)
return cancellableToken
}
// swiftlint:disable:next function_parameter_count
private func performRequest(_ target: Target, request: URLRequest, callbackQueue: DispatchQueue?, progress: Moya.ProgressBlock?, completion: @escaping Moya.Completion, endpoint: Endpoint, stubBehavior: Moya.StubBehavior) -> Cancellable {
switch stubBehavior {
case .never:
switch endpoint.task {
case .requestPlain, .requestData, .requestJSONEncodable, .requestCustomJSONEncodable, .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)
}
}
//真正请求处理
func sendRequest(_ target: Target, request: URLRequest, callbackQueue: DispatchQueue?, progress: Moya.ProgressBlock?, completion: @escaping Moya.Completion) -> CancellableToken {
//生成请求任务task请求
let initialRequest = manager.request(request as URLRequestConvertible)
let validationCodes = target.validationType.statusCodes
let alamoRequest = validationCodes.isEmpty ? initialRequest : initialRequest.validate(statusCode: validationCodes)
return sendAlamofireRequest(alamoRequest, target: target, callbackQueue: callbackQueue, progress: progress, completion: completion)
}
// swiftlint:disable:next cyclomatic_complexity
func sendAlamofireRequest<T>(_ alamoRequest: T, target: Target, callbackQueue: DispatchQueue?, progress progressCompletion: Moya.ProgressBlock?, completion: @escaping Moya.Completion) -> CancellableToken where T: Requestable, T: Request {
// Give plugins the chance to alter the outgoing request
let plugins = self.plugins
plugins.forEach { $0.willSend(alamoRequest, target: target) }
var progressAlamoRequest = alamoRequest
let progressClosure: (Progress) -> Void = { progress in
let sendProgress: () -> Void = {
progressCompletion?(ProgressResponse(progress: progress))
}
if let callbackQueue = callbackQueue {
callbackQueue.async(execute: sendProgress)
} else {
sendProgress()
}
}
// Perform the actual request
if progressCompletion != nil {
switch progressAlamoRequest {
case let downloadRequest as DownloadRequest:
if let downloadRequest = downloadRequest.downloadProgress(closure: progressClosure) as? T {
progressAlamoRequest = downloadRequest
}
case let uploadRequest as UploadRequest:
if let uploadRequest = uploadRequest.uploadProgress(closure: progressClosure) as? T {
progressAlamoRequest = uploadRequest
}
case let dataRequest as DataRequest:
if let dataRequest = dataRequest.downloadProgress(closure: progressClosure) as? T {
progressAlamoRequest = dataRequest
}
default: break
}
}
//请求响应体处理
let completionHandler: RequestableCompletion = { response, request, data, error in
//转换数据
let result = convertResponseToResult(response, request: request, data: data, error: error)
// Inform all plugins about the response
plugins.forEach { $0.didReceive(result, target: target) }
if let progressCompletion = progressCompletion {
switch progressAlamoRequest {
case let downloadRequest as DownloadRequest:
progressCompletion(ProgressResponse(progress: downloadRequest.progress, response: result.value))
case let uploadRequest as UploadRequest:
progressCompletion(ProgressResponse(progress: uploadRequest.uploadProgress, response: result.value))
case let dataRequest as DataRequest:
progressCompletion(ProgressResponse(progress: dataRequest.progress, response: result.value))
default:
progressCompletion(ProgressResponse(response: result.value))
}
}
completion(result)
}
//对请求响应体block处理
progressAlamoRequest = progressAlamoRequest.response(callbackQueue: callbackQueue, completionHandler: completionHandler)
//网络请求request跟task对应 开启任务
progressAlamoRequest.resume()
return CancellableToken(request: progressAlamoRequest)
}
有几个解析一下
//生成请求任务task请求
let initialRequest = manager.request(request as URLRequestConvertible)
调用SessionManager
/// - returns: The created `DataRequest`.
@discardableResult
open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
var originalRequest: URLRequest?
do {
originalRequest = try urlRequest.asURLRequest()
//创建请求TaskConvertible
let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
//同步task请求session.dataTask(with: urlRequest) 生成请求任务
let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
//请求task与deleaget taskDelegate关联,一一对应关系
let request = DataRequest(session: session, requestTask: .data(originalTask, task))
//将网络请求存在delegate中
delegate[task] = request
//是否在构造请求后立即启动请求。默认为“true”
if startRequestsImmediately {
request.resume()
}
return request
} catch {
return request(originalRequest, failedWith: error)
}
}
DataRequest:
struct Requestable: TaskConvertible {
let urlRequest: URLRequest
func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
do {
let urlRequest = try self.urlRequest.adapt(using: adapter)
return queue.sync {
session.dataTask(with: urlRequest)
}
} catch {
throw AdaptError(error: error)
}
}
}
init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {
self.session = session
switch requestTask {
case .data(let originalTask, let task):
taskDelegate = DataTaskDelegate(task: task)
self.originalTask = originalTask
case .download(let originalTask, let task):
taskDelegate = DownloadTaskDelegate(task: task)
self.originalTask = originalTask
case .upload(let originalTask, let task):
taskDelegate = UploadTaskDelegate(task: task)
self.originalTask = originalTask
case .stream(let originalTask, let task):
taskDelegate = TaskDelegate(task: task)
self.originalTask = originalTask
}
//结束后会调用这个方法queue
delegate.error = error
delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }
}
![](https://img.haomeiwen.com/i2789535/a7d15a531937cc6d.png)
总结:
1,创建MoyaProvider对象 配置Alamofire.SessionManager,设置public let session: URLSession和public let delegate: SessionDelegate代理,通过request方法请求,在request方法请求创建DataRequest,DataRequest与TaskDelegate一一对应关联,同步创建task任务,通过 delegate[task] = request方法,将请求request以task为key值储存在delegate(SessionDelegate)
2,在MoyaProvider里sendAlamofireRequest里调用progressAlamoRequest.resume() 开始请求,就是DataRequest里resume方法;
3,网络请求回来通过SessionDelegate代理回调数据,在SessionDelegate代理将数据分发各个请求代理TaskDelegate回调数据出去
4,最后在TaskDelegate 请求完成数据代理中继续执行下去
TaskDelegate
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if let taskDidCompleteWithError = taskDidCompleteWithError {
taskDidCompleteWithError(session, task, error)
} else {
if let error = error {
if self.error == nil { self.error = error }
if
let downloadDelegate = self as? DownloadTaskDelegate,
let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data
{
downloadDelegate.resumeData = resumeData
}
}
//又会开始执行队列中未执行的operation
queue.isSuspended = false
}
}
queue.isSuspended = false方法后
init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {
self.session = session
switch requestTask {
case .data(let originalTask, let task):
taskDelegate = DataTaskDelegate(task: task)
self.originalTask = originalTask
case .download(let originalTask, let task):
taskDelegate = DownloadTaskDelegate(task: task)
self.originalTask = originalTask
case .upload(let originalTask, let task):
taskDelegate = UploadTaskDelegate(task: task)
self.originalTask = originalTask
case .stream(let originalTask, let task):
taskDelegate = TaskDelegate(task: task)
self.originalTask = originalTask
}
//结束后会调用这个方法queue
delegate.error = error
delegate.queue.addOperation {
self.endTime = CFAbsoluteTimeGetCurrent()
}
}
第1步会调用 self.endTime = CFAbsoluteTimeGetCurrent()方法
然后调用DataRequest的response方法
public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self {
delegate.queue.addOperation {
(queue ?? DispatchQueue.main).async {
var dataResponse = DefaultDataResponse(
request: self.request,
response: self.response,
data: self.delegate.data,
error: self.delegate.error,
timeline: self.timeline
)
dataResponse.add(self.delegate.metrics)
completionHandler(dataResponse)
}
}
return self
}
第2步执行 delegate.queue.addOperation {}block方法将响应体数据组装completionHandler回调出去,就是执行sendAlamofireRequest方法completionHandler block
需要一点注意:细心人方法里面有两个queue
一个是TaskDelegate 中 public let queue: OperationQueue,他是通过初始化直接创建的 init(task: URLSessionTask?) 上面执行回调数据都是这个代理queue的
另外一个是SessionManager 中let queue = DispatchQueue(label: "org.alamofire.session-manager." + UUID().uuidString),他是执行创建task的queue,
queue.sync {
session.dataTask(with: urlRequest)
}
两个queue不一样
一个MoyaProvider对象对应一个SessionManager,可以对应多个请求任务task,task与请求和代理是一一对应关系
Moya请求URL参数编码
在 Moya 中,URLEncoding.queryString 是指将参数编码为 URL 查询字符串,并将其添加到请求的 URL 后面。
当使用 URLEncoding.queryString 作为参数编码方式时,Moya 会将参数拼接成一个查询字符串,并将其追加在请求 URL 的后面。例如,以下代码演示了如何使用 URLEncoding.queryString 将参数传递给服务器:
let provider = MoyaProvider<MyAPI>()
provider.request(.getUser(id: 123, name: "John")) { result in
switch result {
case let .success(response):
// 请求成功,处理响应结果
case let .failure(error):
// 请求失败,处理错误信息
}
}
在上述示例中,我们通过 .getUser(id: 123, name: "John") 枚举值向服务器发送了两个参数,分别是 id 和 name。在请求过程中,Moya 将这两个参数编码为查询字符串并追加在请求 URL 的后面,最终发送的请求 URL 类似于:
post 请求就用AFHTTPRequestSerializer
get 请求可以用 AFHTTPRequestSerializer和NSString *queryString = AFQueryStringFromParameters(parameters);方式
NSDictionary *parameters = @{@"param1": @"value1", @"param2": @"value2"};
NSString *urlString = @"https://example.com/api";
NSString *queryString = AFQueryStringFromParameters(parameters);
urlString = [NSString stringWithFormat:@"%@?%@", urlString, queryString];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// 处理响应结果
}];
[task resume];
在 Moya 中,URLEncoding.httpBody 是一种将请求参数编码为 URL 编码格式,并将其放置在 HTTP 请求体中的方式。
当使用 URLEncoding.httpBody 作为参数编码方式时,Moya 会将参数编码为 URL 编码格式,并将其放置在 HTTP 请求体中。例如,以下代码演示了如何使用 URLEncoding.httpBody 将参数传递给服务器:
对应oc AFHTTPRequestSerializer
网友评论