對于iOS開發者來說,
AFNetworking
是我們大家所熟知的,而Alamofire
呢?Alamofire
框架其實就是AFNetworking
兄弟,出自于同一個作者。既是同一個作者,那么他們的使用方法,框架結構上應該也是保持一致的。AFNetworking、Alamofire
一、網絡請求步驟
- 設置請求
url
- 設置
URLRequest
對象,配置請求相關信息 - 創建會話配置
URLSessionConfiguration
- 創建會話
URLSession
- 創建任務和設置請求回調,并發起請求
一般通過以上幾個步來完成網絡請求,當然要根據不同應用場景來配置請求屬性。
二、體驗
發起一個請求:
func responseData() {
let url = "http://onapp.yahibo.top/public/?s=api/test/list"
Alamofire.request(url).responseJSON {
(response) in
switch response.result{
case .success(let json):
print("json:\(json)")
let dict = json as! Dictionary<String, Any>
let list = dict["data"] as! Array<AnyObject>
guard let result = [UserModel1].deserialize(from: list) else{return}
self.observable.onNext(result as [Any])
break
case .failure(let error):
print("error:\(error)")
break
}
}
}
-
responseJSON
為相應類型,指定為json
數據類型 -
response
是Alamofire
對服務器響應結果的封裝 - 使用常規解包獲取數據
headimg
- 通過
HandyJSON
轉換為模型數據,供UI
展示
直接通過Alamofire
發起請求通過一個閉包返回請求結果,不需要二次封裝使用簡單。這里我們沒有標明請求類型,沒有請求參數,那Alamofire
是如何封裝這些請求參數的呢,點擊進入查看方法定義:
public func request(
_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil)
-> DataRequest
{
return SessionManager.default.request(
url,
method: method,
parameters: parameters,
encoding: encoding,
headers: headers
)
}
這里已經提供了請求所需要的參數,并設置了默認值,因此外界在沒有指定方法時默認為get
方式。根據實際開發需求設置響應的參數:
Alamofire.request(url,method: .post,parameters: ["page":"1","size":"20"]).responseJSON
這是我們開發中常見的設置請求方式,請求參數,這里的url
支持多種數據類型,可以是String、URL、URLRequest
等類型,為什么這么設計呢?因為在項目中可能當前我們跟前有一個String
類型的連接,也有可能是個URL
類型的連接,這時候在不需要轉換的情況下就可以直接使用,方便快捷,更加靈活。
效果如下:
三、URLSession
同樣在Alamofire
中也是對URLSession
封裝的,在OC
中為NSURLSession
,其實是一樣的。一般網絡請求分三個步驟:
1、設置URL請求地址
let url = URL.init(string: "協議://主機地址/路徑/參數1&參數2")!
- 協議:指定
http
協議還是https
協議 - 主機:即服務器地址
ip
地址或綁定ip
的域名 - 路徑:項目在服務器上的位置
- 參數:即
get
參數拼接在連接上
2、設置URLRequest屬性
var request = URLRequest.init(url: url)
request.httpMethod = HTTPMethod.post.rawValue
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let postData = ["username":"hibo","password":"123456"]
request.httpBody = try?JSONSerialization.data(withJSONObject: postData, options: [])
request.timeoutInterval = 30
request.cachePolicy = .useProtocolCachePolicy
-
httpMethod
設置請求方式post
或get
-
setValue
設置請求頭信息 -
httpBody
設置請求參數,參數打包在請求體中 -
timeoutInterval
設置請求超時時間 -
cachePolicy
設置網絡請求緩存策略
通過以上的參數設置,能夠感受到發送一次請求是多么不容易,因此網絡請求是必須要被封裝的
3、發起請求
URLSession.shared.dataTask(with: request) { (data, response, error) in
print("*******網絡請求*******")
do {
let list = try JSONSerialization.jsonObject(with: data!, options: .allowFragments)
print(list)
}catch{
print(error)
}
}.resume()
-
URLSession.shared
為全局共享單例會話對象 - 調用
dataTask
創建網絡請求任務 -
resume
默認為掛起狀態,調用重新啟動網絡請求任務 -
data
:請求到的數據流,通過JSONSerialization
序列化為json
格式使用
四、URLSessionConfiguration
在URLSession.shared
中內部已經配置了該項,此項為會話配置項,一般使用都會進行配置以適用于不同場景。查看該類如下:
open class var `default`: URLSessionConfiguration { get }
open class var ephemeral: URLSessionConfiguration { get }
@available(iOS 8.0, *)
open class func background(withIdentifier identifier: String) -> URLSessionConfiguration
-
default
:默認模式,常用模式,在該模式下系統會創建持久化緩存,并在用戶的鑰匙串中保存證書 -
ephemeral
:不支持持久性存儲,所有內容的會隨著session
的生命周期結束而釋放 -
background
:與default
模式類似,在該模式下會創建一個獨立線程來傳輸網絡請求數據,可以在后臺乃至APP關閉的時候也可以進行數據傳輸
創建一個會話:
let configuration = URLSessionConfiguration.background(withIdentifier: "request_id")
let session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
session.dataTask(with: request) { (data, response, error) in
print("*******網絡請求*******")
do {
let list = try JSONSerialization.jsonObject(with: data!, options: .allowFragments)
print(list)
}catch{
print(error)
}
}.resume()
- 設置一個唯一會話標識,通過標識來區分不同的會話任務
- 遵循
URLSessionDelegate
代理,實現代理方法,在本類中監控任務進度
下載任務:
let configuration = URLSessionConfiguration.background(withIdentifier: "request_id")
let session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
session.downloadTask(with: url).resume()
注意在使用background
模式時一定要開啟后臺下載權限,否則無法完成后臺下載并回調數據。需要以下兩步才能完成:
1、開啟后臺下載權限
var backgroundHandler: (()->Void)? = nil
//設置此處開啟后臺下載權限
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
self.backgroundHandler = completionHandler
}
2、實現SessionDelegate
代理方法,調用閉包方法,通知系統更新屏幕
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
print("后臺任務下載回來")
DispatchQueue.main.async {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, let backgroundHandle = appDelegate.backgroundHandler else { return }
backgroundHandle()
}
}
蘋果官方給出需要實現以上兩個方法來完成后臺下載,通知系統及時更新屏幕。官方文檔
五、相關屬性
1、常規屬性
-
identifier:
配置對象的后臺會話標識符 -
httpAdditionalHeaders:
與請求一起發送的附加頭文件字典 -
networkServiceType:
網絡服務的類型 -
allowsCellularAccess:
一個布爾值,用于是否應通過蜂窩網絡進行連接 -
timeoutIntervalForRequest:
等待附加數據的超時時間 -
timeoutIntervalForResource:
資源請求允許的最大時間范圍 -
sharedContainerIdentifier:
應將后臺URL會話中的文件下載到的共享容器的標識符 -
waitsForConnectivity:
一個布爾值,指示會話是否應等待連接變為可用還是立即失敗
2、設置Cookie策略
-
httpCookieAcceptPolicy:
決定何時接受cookie的策略常量 -
httpShouldSetCookies:
一個布爾值,確定請求是否包含來自cookie
存儲區的cookie
-
httpCookieStorage
:用于會話中存儲cookie
的cookie
存儲區 -
HTTPCookie:
該對象為不可變對象,從包含cookie
屬性的字典初始化,支持兩個不同的cookie版本,v0、v1
3、設置安全策略
-
TLS協議:
用于在兩個通信應用程序之間提供保密性和數據完整性 -
tlsMaximumSupportedProtocol:
在此會話中建立連接時客戶端應請求的最大TLS協議
版本 -
tlsMinimumSupportedProtocol:
協議協商期間應接受的最小TLS協議
-
urlCredentialStorage:
為身份驗證提供憑據的憑據存儲區
4、設置緩存策略
-
urlCache:
用于為會話中的請求提供緩存響應的URL
緩存 -
requestCachePolicy:
決定何時從緩存中返回響應的預定義常量
5、支持后臺轉移
-
sessionSendsLaunchEvents:
一個布爾值,指示當傳輸完成時,應用程序應在后臺恢復還是啟動 -
isDiscretionary:
一個布爾值,用于確定后臺任務是否可以由系統自行安排已獲得最佳性能 -
shouldUseExtendedBackgroundIdleMode:
一個布爾值,指示當應用程序轉移到后臺時是否應保持TCP
連接打開
6、支持自定義協議
-
protocolClasses:
在會話中處理請求的額外協議子類的數組 -
URLProtocol:
該對象用來處理加載協議特定URL
數據
7、支持多路徑TCP
-
multipathServiceType:
指定用于通過Wi-Fi
和蜂窩接口傳輸數據的多路徑TCP
連接策略的服務類型
8、設置HTTP策略和代理屬性
-
httpMaximumConnectionsPerHost:
同時連接到給定主機的最大數量 -
httpShouldUsePipelining:
一個布爾值,用于確定會話是否使用HTTP
流水線 -
connectionProxyDictionary:
包含相關要在此會話中使用的代理信息的字典
9、支持連接更改
-
waitsForConnectivity:
一個布爾值,指示會話應等待連接可用還是立即失敗
一個請求任務就有如此多的配置屬性,可想而知對一個網絡框架的整合,工作量也是非常大的。接下來我們就一步步來了解一下Alamofire是如何一步步整合的。