KM的博客.

Alamfire源码

字数统计: 2.2k阅读时长: 12 min
2020/06/30

Alamfire Github地址

1、Request分析

Request准守的Protocol

  • Equatable

  • Hashable

  • CustomStringConvertible

  • Downloadable

  • UploadableConvertible

Equatable
1
2
3
4
5
extension Request: Equatable {
public static func ==(lhs: Request, rhs: Request) -> Bool {
return lhs.id == rhs.id
}
}
Hashable
1
2
3
4
5
extension Request: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
CustomStringConvertible
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


extension Request: CustomStringConvertible {
/// A textual representation of this instance, including the `HTTPMethod` and `URL` if the `URLRequest` has been
/// created, as well as the response status code, if a response has been received.
public var description: String {
guard let request = performedRequests.last ?? lastRequest,
let url = request.url,
let method = request.httpMethod else { return "No request created yet." }

let requestDescription = "\(method) \(url.absoluteString)"

return response.map { "\(requestDescription) (\($0.statusCode))" } ?? requestDescription
}
}
Downloadable
1
2
3
4
5
6
7
8
9
10
11
12
13
 /// Type describing the source used to create the underlying `URLSessionDownloadTask`.

public enum Downloadable {

/// Download should be started from the `URLRequest` produced by the associated `URLRequestConvertible` value.

case request(URLRequestConvertible)

/// Download should be started from the associated resume `Data` value.

case resumeData(Data)

}
UploadableConvertible
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/// A type that can produce an `UploadRequest.Uploadable` value.
public protocol UploadableConvertible {
/// Produces an `UploadRequest.Uploadable` value from the instance.
///
/// - Returns: The `UploadRequest.Uploadable`.
/// - Throws: Any `Error` produced during creation.
func createUploadable() throws -> UploadRequest.Uploadable
}

extension UploadRequest.Uploadable: UploadableConvertible {
public func createUploadable() throws -> UploadRequest.Uploadable {
return self
}
}

/// A type that can be converted to an upload, whether from an `UploadRequest.Uploadable` or `URLRequestConvertible`.
public protocol UploadConvertible: UploadableConvertible & URLRequestConvertible {}

初始化字段

id: UUID为request提供唯一标识,用于hash、相等
underlyingQueue: DispatchQueue 内部异步操作的串行队列
serializationQueue: DispatchQueue 序列化使用的队列
eventMonitor: EventMonitor? 事件监控
interceptor: RequestInterceptor? 拦截器(重试器、适配器)
delegate: RequestDelegate?

Result定义State枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class Request {

public enum State {
case initialized //初始化
case resumed //恢复
case suspended //挂起
case cancelled // 取消
case finished //完成
func canTransitionTo(_ state: State) -> Bool {
switch (self, state) {
case (.initialized, _):
return true
case (_, .initialized), (.cancelled, _), (.finished, _):
return false
case (.resumed, .cancelled), (.suspended, .cancelled), (.resumed, .suspended), (.suspended, .resumed):
return true
case (.suspended, .suspended), (.resumed, .resumed):
return false
case (_, .finished):
return true
}
}
}

// MARK: - Initial State
// MARK: - Mutable State
// MARK: Progress
// MARK: Redirect Handling
// MARK: Cached Response Handling
// MARK: URLCredential
// MARK: Validators
// MARK: URLRequests
// MARK: HTTPURLResponse

// MARK: Tasks
/// All `URLSessionTask`s created on behalf of the `Request`.
public var tasks: [URLSessionTask] { return protectedMutableState.directValue.tasks }
/// First `URLSessionTask` created on behalf of the `Request`.
public var firstTask: URLSessionTask? { return tasks.first }
/// Last `URLSessionTask` crated on behalf of the `Request`.
public var lastTask: URLSessionTask? { return tasks.last }
/// Current `URLSessionTask` created on behalf of the `Request`.
public var task: URLSessionTask? { return lastTask }

///MARK: Metrics

///MARK: Retry Count
public var retryCount: Int { return protectedMutableState.directValue.retryCount }
///MARK: Error
public fileprivate(set) var error: AFError? {
get { return protectedMutableState.directValue.error }
set { protectedMutableState.write { $0.error = newValue } }
}

// MARK: - Internal Event API
// All API must be called from underlyingQueue.(所有的API必须从底层队列调用)

...
}

Task相关: cancle/resume/suspend

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// MARK: Task Creation
/// - Returns: The `URLSessionTask` created.
func task(for request: URLRequest, using session: URLSession) -> URLSessionTask {
fatalError("Subclasses must override.")
}
// MARK: State

@discardableResult
public func cancel() -> Self {
protectedMutableState.write { mutableState in
guard mutableState.state.canTransitionTo(.cancelled) else { return }

mutableState.state = .cancelled

underlyingQueue.async { self.didCancel() }

guard let task = mutableState.tasks.last, task.state != .completed else {
underlyingQueue.async { self.finish() }
return
}

// Resume to ensure metrics are gathered.
task.resume()
task.cancel()
underlyingQueue.async { self.didCancelTask(task) }
}

return self
}

/// Suspends the instance.
///
/// - Returns: The instance.
@discardableResult
public func suspend() -> Self {
protectedMutableState.write { mutableState in
guard mutableState.state.canTransitionTo(.suspended) else { return }

mutableState.state = .suspended

underlyingQueue.async { self.didSuspend() }

guard let task = mutableState.tasks.last, task.state != .completed else { return }

task.suspend()
underlyingQueue.async { self.didSuspendTask(task) }
}

return self
}

/// Resumes the instance.
///
/// - Returns: The instance.
@discardableResult
public func resume() -> Self {
protectedMutableState.write { mutableState in
guard mutableState.state.canTransitionTo(.resumed) else { return }

mutableState.state = .resumed

underlyingQueue.async { self.didResume() }

guard let task = mutableState.tasks.last, task.state != .completed else { return }

task.resume()
underlyingQueue.async { self.didResumeTask(task) }
}

return self
}

State

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// Protected `MutableState` value that provides thread-safe access to state values.
fileprivate let protectedMutableState: Protector<MutableState> = Protector(MutableState())

/// `State` of the `Request`.
public var state: State { return protectedMutableState.directValue.state }
/// Returns whether `state` is `.initialized`.
public var isInitialized: Bool { return state == .initialized }
/// Returns whether `state is `.resumed`.
public var isResumed: Bool { return state == .resumed }
/// Returns whether `state` is `.suspended`.
public var isSuspended: Bool { return state == .suspended }
/// Returns whether `state` is `.cancelled`.
public var isCancelled: Bool { return state == .cancelled }
/// Returns whether `state` is `.finished`.
public var isFinished: Bool { return state == .finished }

可变状态MutableState

通过结构体MutableState封装,包括进度、重定向、缓存、cURL、响应序列化、凭证、请求、task、metrics、重试次数、错误。

1
2
/// Protected `MutableState` value that provides thread-safe access to state values.
fileprivate let protectedMutableState: Protector<MutableState> = Protector(MutableState())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
struct MutableState {
/// State of the `Request`.
var state: State = .initialized
/// `ProgressHandler` and `DispatchQueue` provided for upload progress callbacks.
var uploadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)?
/// `ProgressHandler` and `DispatchQueue` provided for download progress callbacks.
var downloadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)?
/// `RedirectHandler` provided for to handle request redirection.
var redirectHandler: RedirectHandler?
/// `CachedResponseHandler` provided to handle response caching.
var cachedResponseHandler: CachedResponseHandler?
/// Closure called when the `Request` is able to create a cURL description of itself.
var cURLHandler: ((String) -> Void)?
/// Response serialization closures that handle response parsing.
var responseSerializers: [() -> Void] = []
/// Response serialization completion closures executed once all response serializers are complete.
var responseSerializerCompletions: [() -> Void] = []
/// Whether response serializer processing is finished.
var responseSerializerProcessingFinished = false
/// `URLCredential` used for authentication challenges.
var credential: URLCredential?
/// All `URLRequest`s created by Alamofire on behalf of the `Request`.
var requests: [URLRequest] = []
/// All `URLSessionTask`s created by Alamofire on behalf of the `Request`.
var tasks: [URLSessionTask] = []
/// All `URLSessionTaskMetrics` values gathered by Alamofire on behalf of the `Request`. Should correspond
/// exactly the the `tasks` created.
var metrics: [URLSessionTaskMetrics] = []
/// Number of times any retriers provided retried the `Request`.
var retryCount = 0
/// Final `AFError` for the `Request`, whether from various internal Alamofire calls or as a result of a `task`.
var error: AFError?
}
Redirects
  • 如果多次设置重定向hander是逻辑错误的而且会引起crash
  • 如果设置了redirect handler,当redirect response 响应的话,会使用到实例Request
Cached Responses
  • Sets the cached response handler for the Request which will be used when attempting to cache a response.

  • Note: Attempting to set the cache handler more than once is a logic error and will crash.

Clearup

1
2
3
4
5
/// Final cleanup step executed when the instance finishes response serialization.
func cleanup() {
delegate?.cleanup(after: self)
// No-op: override in subclass
}

DataRequest

1
2
3
4
5
/// DataRequest是Request子类,使用URLSessionDataTask处理内存中下载的Data

public class DataRequest: Request {

}

DownloadRequest

1
2
3
4
5
6
/// `Request` subclass which downloads `Data` to a file on disk using `URLSessionDownloadTask`.

/// DownloadRequest也是Request子类,使用URLSessionDownloadTask处理下载到硬盘中的Data。
public class DownloadRequest也是Request子类,使用: Request {

}

UploadRequest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58


/// `DataRequest` subclass which handles `Data` upload from memory, file, or stream using `URLSessionUploadTask`.

public class UploadRequest: DataRequest {

/// Type describing the origin of the upload, whether `Data`, file, or stream.

public enum Uploadable {

/// Upload from the provided `Data` value.

case data(Data)

/// Upload from the provided file `URL`, as well as a `Bool` determining whether the source file should be

/// automatically removed once uploaded.

case file(URL, shouldRemove: Bool)

/// Upload from the provided `InputStream`.

case stream(InputStream)

}



// MARK: **Initial State**



/// The `UploadableConvertible` value used to produce the `Uploadable` value for this instance.

public let upload: UploadableConvertible



/// `FileManager` used to perform cleanup tasks, including the removal of multipart form encoded payloads written

/// to disk.

public let fileManager: FileManager



// MARK: **Mutable State**



/// `Uploadable` value used by the instance.

public var uploadable: Uploadable?



/// Creates an `UploadRequest` using the provided parameters.
......

2、Session

3、Result枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/// Result.swift
import Foundation

public enum Result<Value> {
case success(Value)
case failure(Error)

/// Returns `true` if the result is a success, `false` otherwise.
public var isSuccess: Bool {
switch self {
case .success:
return true
case .failure:
return false
}
}

/// Returns `true` if the result is a failure, `false` otherwise.
public var isFailure: Bool {
return !isSuccess
}

/// Returns the associated value if the result is a success, `nil` otherwise.
public var value: Value? {
switch self {
case .success(let value):
return value
case .failure:
return nil
}
}

/// Returns the associated error value if the result is a failure, `nil` otherwise.
public var error: Error? {
switch self {
case .success:
return nil
case .failure(let error):
return error
}
}
}

// MARK: - CustomStringConvertible

extension Result: CustomStringConvertible {
/// The textual representation used when written to an output stream, which includes whether the result was a
/// success or failure.
public var description: String {
switch self {
case .success:
return "SUCCESS"
case .failure:
return "FAILURE"
}
}
}

// MARK: - CustomDebugStringConvertible

extension Result: CustomDebugStringConvertible {
/// The debug textual representation used when written to an output stream, which includes whether the result was a
/// success or failure in addition to the value or error.
public var debugDescription: String {
switch self {
case .success(let value):
return "SUCCESS: \(value)"
case .failure(let error):
return "FAILURE: \(error)"
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public enum AFError: Error {
/// The underlying reason the parameter encoding error occurred.
///
/// - missingURL: The URL request did not have a URL to encode.
/// - jsonEncodingFailed: JSON serialization failed with an underlying system error during the
/// encoding process.
/// - propertyListEncodingFailed: Property list serialization failed with an underlying system error during
/// encoding process.
public enum ParameterEncodingFailureReason {
case missingURL
case jsonEncodingFailed(error: Error)
case propertyListEncodingFailed(error: Error)
}

/// The underlying reason the multipart encoding error occurred.
public enum MultipartEncodingFailureReason {
case bodyPartURLInvalid(url: URL)
case bodyPartFilenameInvalid(in: URL)
case bodyPartFileNotReachable(at: URL)
case bodyPartFileNotReachableWithError(atURL: URL, error: Error)
case bodyPartFileIsDirectory(at: URL)
case bodyPartFileSizeNotAvailable(at: URL)
case bodyPartFileSizeQueryFailedWithError(forURL: URL, error: Error)
case bodyPartInputStreamCreationFailed(for: URL)

case outputStreamCreationFailed(for: URL)
case outputStreamFileAlreadyExists(at: URL)
case outputStreamURLInvalid(url: URL)
case outputStreamWriteFailed(error: Error)

case inputStreamReadFailed(error: Error)
}
public enum ResponseValidationFailureReason {
case dataFileNil
case dataFileReadFailed(at: URL)
case missingContentType(acceptableContentTypes: [String])
case unacceptableContentType(acceptableContentTypes: [String], responseContentType: String)
case unacceptableStatusCode(code: Int)
}
public enum ResponseSerializationFailureReason {
case inputDataNil
case inputDataNilOrZeroLength
case inputFileNil
case inputFileReadFailed(at: URL)
case stringSerializationFailed(encoding: String.Encoding)
case jsonSerializationFailed(error: Error)
case propertyListSerializationFailed(error: Error)
}

case invalidURL(url: URLConvertible)
case parameterEncodingFailed(reason: ParameterEncodingFailureReason)
case multipartEncodingFailed(reason: MultipartEncodingFailureReason)
case responseValidationFailed(reason: ResponseValidationFailureReason)
case responseSerializationFailed(reason: ResponseSerializationFailureReason)
}

JSONSerialization编解码

1
class JSONSerialization : NSObject

Overview

您可以使用JSONSerialization类将JSON转换为Foundation对象,并将Foundation对象转换为JSON。

可能转换为JSON的Foundation对象必须具有以下属性:

其他规则可能适用。如调用isValidJSONObject(_:)或尝试进行转换是确定给定对象是否可以转换为JSON的确定方法数据。

线程安全在iOS 7和更高版本以及macOS 10.9和更高版本上,**JSONSerialization是线程安全的**。

Creating a JSON Object

class func jsonObject(with: Data, options: JSONSerialization.ReadingOptions) -> Any

Returns a Foundation object from given JSON data.

class func jsonObject(with: InputStream, options: JSONSerialization.ReadingOptions) -> Any

Returns a Foundation object from JSON data in a given stream.

Creating JSON Data

class func data(withJSONObject: Any, options: JSONSerialization.WritingOptions) -> Data

Returns JSON data from a Foundation object.

class func writeJSONObject(Any, to: OutputStream, options: JSONSerialization.WritingOptions, error: NSErrorPointer) -> Int

Writes a given JSON object to a stream.

class func isValidJSONObject(Any) -> Bool

Returns a Boolean value that indicates whether a given object can be converted to JSON data.

拓展阅读

AFNetwork姊妹篇

URLSession全家桶

AlamFire结构解析

戴铭JSONDecoder

CATALOG
  1. 1. Alamfire Github地址
  2. 2. 1、Request分析
    1. 2.0.1. Request准守的Protocol
      1. 2.0.1.1. Equatable
      2. 2.0.1.2. Hashable
      3. 2.0.1.3. CustomStringConvertible
      4. 2.0.1.4. Downloadable
      5. 2.0.1.5. UploadableConvertible
    2. 2.0.2. 初始化字段
    3. 2.0.3. Result定义State枚举
    4. 2.0.4. Task相关: cancle/resume/suspend
    5. 2.0.5. State
    6. 2.0.6. 可变状态MutableState
      1. 2.0.6.1. Redirects
      2. 2.0.6.2. Cached Responses
    7. 2.0.7. Clearup
    8. 2.0.8. DataRequest
    9. 2.0.9. DownloadRequest
    10. 2.0.10. UploadRequest
  • 3. 2、Session
  • 4. 3、Result枚举
    1. 4.0.1. JSONSerialization编解码
  • 5. Overview
  • 6.
    1. 6.1. Creating a JSON Object
    2. 6.2. Creating JSON Data
    3. 6.3. 拓展阅读
      1. 6.3.1. AFNetwork姊妹篇
      2. 6.3.2. URLSession全家桶
      3. 6.3.3. AlamFire结构解析
      4. 6.3.4. 戴铭JSONDecoder