本文共 8991 字,大约阅读时间需要 29 分钟。
Alomafire 是一个网络请求框架,其同 AFNetworking 框架是同一个创作团队,只是后者是使用 Objective-C 写的,而该框架是用 Swift 写的。
枚举
结构体
协议
别名
扩展
类
AFError 枚举遵循 Error 协议,用来描述 Alomafire 框架返回的错误,部分代码如下:
public enum AFError: Error { case invalidURL(url: URLConvertible) case parameterEncodingFailed(reason: ParameterEncodingFailureReason) case multipartEncodingFailed(reason: MultipartEncodingFailureReason) case responseValidationFailed(reason: ResponseValidationFailureReason) case responseSerializationFailed(reason: ResponseSerializationFailureReason)}
该枚举中定义了不同类型的错误,这些错误都通过关联值来关联不同的错误原因。并且这些关联的类型,除了 URLConvertible 是一个协议外,其他都是在 AFError 中声明的枚举类型。
HTTPMethod 是一个原始值为 String 的枚举类型,定义了不同的网络请求类型,如 PUT、GET、POST、DELETE 等等。
public enum Result{ case success(Value) case failure(Error) ...}
Result 作为描述服务器返回数据的枚举类型,实际上是将成功返回的信息关联在 success 枚举值中,而将错误信息关联在 failure 枚举值中。
struct AdaptError: Error { let error: Error}extension Error { var underlyingAdaptError: Error? { return (self as? AdaptError)?.error }}
AdaptError 同样遵循了 Error 协议,且只包含了一个 error 变量,该变量同样也遵循 Error 协议。
并且,通过扩展 Error 协议,为其声明了一个 underlyingAdaptError 用来获取 AdaptError 结构所存储的 error 变量。
遵循了 ParameterEncoding 协议,提供对请求链接的编码,在编码过程中,会将编码后的参数追加到请求链接后,或是添加到请求体中。
对于数组参数的编码提供了跟随 []
和不跟随 []
两种格式,真假值也提供了数值和字符串两种形式。
如果是将参数追加到请求体中,还会添加如下头信息:
"Content-Type":"application/x-www-form-urlencoded; charset=utf-8"
同样遵循 ParameterEncoding 协议,会将参数编码后添加到请求体中,并添加如下头信息:
"Content-Type":"application/json"
同样遵循 ParameterEncoding 协议,会将参数编码后添加到请求体中,并添加如下头信息:
"Content-Type":"application/x-plist"
参数的编码格式分为 xml 和 binary 两种。
Timeline 结构体中保存了一个请求开始到服务器响应结束过程中所涉及的时间,包括请求开始时间、接收到服务器返回的第一个字节的时间、请求结束时间、返回数据序列化结束时间,还提供了根据前面几个时间得到的响应延迟时间、请求时间、序列化时间和整个网络从请求开始到数据序列化解析结束的总时间。
作为一个结构体保存请求信息、响应信息以及从服务器返回的数据和解析后的实例。
作为一个结构体保存请求信息、响应信息以及下载的数据和解析后的实例。
DataResponseSerializer 结构体遵循 DataResponseSerializerProtocol 协议,并且初始化参数是一个逃逸闭包,
public struct DataResponseSerializer: DataResponseSerializerProtocol { public typealias SerializedObject = Value public var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result public init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result ) { self.serializeResponse = serializeResponse }}
该结构体的实例保存着序列化数据的闭包,实际使用时,调用该闭包得到结果,然后使用该结果初始化一个 DataResponse 实例。框架中并没有为 DataResponseSerializer 声明创建 DataResponse 实例的方法,而是通过扩展任务 DataRequest 的方式,声明了诸如 responseJSON、responsePropertyList、responseString 的方法,这些方法会向任务代理的队列中添加一个创建 DataResponse 实例的任务,并将该实例作为闭包参数传递给调用者提供的闭包任务。
如下所示,该协议声明了一个返回 URL 类型变量的函数,该请求链接符合 RFC 2396 文档,并且可以用来构造 request 网络请求。
public protocol URLConvertible { func asURL() throws -> URL}
该框架中为 String、URL、URLComponents 扩展了 URLConvertible 协议,这意味着我们可以直接使用这些类型的参数构造网络请求实例。
如下,该协议定义了一个返回 URLRequest 类型变量的函数,所有遵循该协议的类型都可以用来构造一个网络请求。
public protocol URLRequestConvertible { func asURLRequest() throws -> URLRequest}extension URLRequestConvertible { public var urlRequest: URLRequest? { return try? asURLRequest() }}
同样的,为了便利,该协议扩展了一个 urlRequest 变量来获取 asURLRequest() 函数的返回值。
RequestAdapter 协议定义了一个获取 URLRequest 类型变量的函数,但是该方法的参数就是一个 URLRequest 变量。
实际上该方法提供了遵循该协议的类型能够对传入的 URLRequest 参数进行修改,而后返回的能力。可以将之称为网络请求信息适配器,如此,只要提供一个遵循该协议的变量,当构造请求信息时,就可以根据需要进行修改。public protocol RequestAdapter { func adapt(_ urlRequest: URLRequest) throws -> URLRequest}
RequestRetrier 协议定义了一个方法,用来判断是否允许一个出错的请求重新发起请求。
public typealias RequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval) -> Voidpublic protocol RequestRetrier { func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion)}
ParameterEncoding 协议定义了一个编码方法,遵循该协议的类型,需要实现该方法,提供将请求信息进行编码的方式。
public protocol ParameterEncoding { func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest}
Alamofire 框架中,提供了 URLEncoding、JSONEncoding 和 PropertyListEncoding 三种编码方式,如果需要可以自定义遵循该协议的编码类型。
所有序列化响应类型都需要遵循该协议,其声明了一个闭包,用来将数据序列化为一个实例变量。
public protocol DataResponseSerializerProtocol { associatedtype SerializedObject var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result{ get }}
所有遵循该协议的类型,都可以调用该闭包,从而序列化返回的数据。
public typealias HTTPHeaders = [String: String]
public typealias Parameters = [String: Any]
URLRequest 作为 Foundation 框架中的类型,同时也是保存网络请求信息的结构体。
扩展了一个初始化方法,指定请求地址、请求方式和额外的请求头变量。
public init(url: URLConvertible, method: HTTPMethod, headers: HTTPHeaders? = nil) throws { let url = try url.asURL() self.init(url: url) httpMethod = method.rawValue if let headers = headers { for (headerField, headerValue) in headers { setValue(headerValue, forHTTPHeaderField: headerField) } }}
并且,使用默认的缓存策略以及默认的 60 秒超时时间。
作为一个会话的管理类,自然的提供了一个该类的全局静态变量,以供使用。
public static let `default`: SessionManager = { let configuration = URLSessionConfiguration.default configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders return SessionManager(configuration: configuration)}()
返回的默认管理实例,保存着默认的会话设置,以及 HTTP 的几个头报文信息(defaultHTTPHeaders),其同样是一个以闭包执行为初始化的全局静态变量,返回的信息类似如下:
["Accept-Language": "zh-Hans-US;q=1.0, en;q=0.9", "User-Agent": "Test-Alamofire/1.0 (Test.Test-Alamofire; build:1; iOS 12.4.0) Alamofire/4.8.2", "Accept-Encoding": "gzip;q=1.0, compress;q=0.5"]
SessionManager 类中维护了一个 URLSession 类实例 session ,实际的会话操作都是由该实例实现的。同时,其所声明的 SessionDelegate 类型的代理示例 delegate 也是该 session 的代理对象。
而 startRequestsImmediately 属性则表示是否在构造请求信息后直接进行请求操作,默认为 true 。
该类中还有一个计算属性 retrier, 其实际上是代理 delegate 中的 retrier 属性,由其决定是否在构造请求信息时遇到错误时,是否重新构造请求信息。如果为否,那么则由 startRequestsImmediately 属性决定是否直接开始发起网络请求任务。
经过初始化后的 SessionManager 实例,便可以调用相关的 request、download、upload、stream 方法创建相关的任务,包括 URLSessionDataTask、URLSessionUploadTask、URLSessionDownloadTask、URLSessionStreamTask 等。并且,这些任务信息,会保存在框架中相应的 DataRequest、DownloadRequest、UploadRequest、StreamRequest 实例变量中,这些实例有一个共同的父类 Request ,其声明了一些通用属性。
SessionDelegate 虽然名为代理,用来处理请求的回调任务,但是其实际是一个继承了 NSObject 的类。该类声明了许多闭包类型的变量,然后通过扩展的方式遵循 URLSessionDelegate、URLSessionTaskDelegate、URLSessionDataDelegate、URLSessionDownloadDelegate 和 URLSessionStreamDelegate 协议,在实现这些协议的方法中调用相应的闭包,从而实现了代理功能。
Request 作为各种网络请求的父类,定义了一些通用属性。其主要的初始化函数如下:
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 } delegate.error = error delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }}
RequestTask 作为一个枚举类型,关联了原始的请求信息以及根据该请求信息生成的网络请求任务。在初始化过程中,总是使用任务实例,初始化一个任务代理。这个代理类实例将执行所有网络请求的回调任务。
然后,该 Request 类还定义了开始任务,挂起任务和取消任务三个方法,并发出相应的通知。
对于请求数据、下载数据、上传数据、流通信任务,分别定义了三个子类:DataRequest、DownloadRequest、UploadRequest、StreamRequest。
NetworkReachabilityManager 是网络状态监听类,通过该类,可以设置一些网络变化的操作。
下面两个枚举类型分别定义了网络状态和网络类型:
public enum NetworkReachabilityStatus { case unknown case notReachable case reachable(ConnectionType)}public enum ConnectionType { case ethernetOrWiFi case wwan}
而设置网络变化的操作,则是需要声明一个 Listener 类型的闭包,其有一个网络状态参数,表示网络状态的变化。
public typealias Listener = (NetworkReachabilityStatus) -> Void
TaskDelegate 是继承了 NSObject 的类,从字面意思看,其应当是作为任务的代理使用,实际上其并没有明确的遵循 URLSessionTaskDelegate 协议,而是使用 @objc 指明所实现的方法,形式如下:
@objc(URLSession:task:didReceiveChallenge:completionHandler:)
TaskDelegate 实例由一个 URLSessionTask 实例初始化,即其保存着任务信息,同时也是任务回调事件的执行者。
实际使用的 DataTaskDelegate、DownloadTaskDelegate 和 UploadTaskDelegate 类都继承自 TaskDelegate 类。
虽然每个任务都有自己的代理,但是如果创建该任务的会话的代理 SessionDelegate 实例已经设置了需要执行的回调任务,那么网络请求任务本身的代理便不会执行相应的代理方法。但是,任务结束代理方法和流通信任务代理方法除外。
在 Alamofire 框架中,Alamofire.swift 文件中,定义了一些全局函数,用来执行获取(request)、下载(download)、上传(upload)和流通信(stream)。
查看这些全局函数,即可知,他们其实只是对 SessionManager 中方法的封装,通过 SessionManager 的 default 方法获取一个会话管理对象,而后调用该对象的相应方法实现相关的任务请求。
转载地址:http://spdws.baihongyu.com/