XMNetwoking 是咱們團隊開源的一個網絡庫,詳見:GitHubphp
XMNetworking 是一個輕量的、簡單易用但功能強大的網絡庫,基於 AFNetworking 3.0 封裝。
其中,XM
前綴是咱們團隊 Xcode-Men 的縮寫。英文文檔ios
XMNetworking.pnggit
如上圖所示,XMNetworking 採用中心化的設計思想,由 XMCenter
統一發起並管理全部的 XMRequest
請求,並可經過 XMCenter
給全部請求配置回調線程、公共 Server URL、Header、Parameter 等信息,同時也能夠 Block 注入的方式實現自定義的響應結果處理邏輯,如數據模型轉換、業務錯誤碼判斷、網絡緩存等。另外增長了 XMEgine
這一層是爲了隔離底層第三方庫依賴,便於之後切換其餘底層網絡庫或本身實現底層邏輯。github
在你工程的 Podfile
文件中添加以下一行,並執行 pod install
或 pod update
。api
pod 'XMNetworking'
注意: XMNetworking
已經包含了 AFNetworking
3.1.0 的源代碼,因此你工程裏的 Podfile
文件不能再添加 pod AFNetworking
去導入 AFNetworking
,不然會有衝突!緩存
與 CocoaPods 不一樣的是,Carthage 是一個去中心化的第三方依賴庫管理工具,它自動幫你編譯所依賴的第三方庫並以 framework 形式提供給你。安全
你能夠經過 Homebrew 執行如下命令來安裝 Carthage:服務器
$ brew update $ brew install carthage
成功安裝完 Carthage 後,在你工程的 Cartfile
文件中添加以下一行:網絡
github "kangzubin/XMNetworking"
而後執行 carthage update --platform ios
命令生成 framework 包,並把生成的 XMNetworking.framework
拖拽到你的工程中。session
注意: XMNetworking
已經包含了 AFNetworking
3.1.0 的源代碼,因此你無需經過 Carthage 生成 AFNetworking.framework
導到你工程中,不然會有衝突!
下載 XMNetworking
子文件夾的全部內容,並把其中的源文件添加(拖放)到你的工程中。
#import <XMNetworking/XMNetworking.h>
#import "XMNetworking.h"
[XMCenter setupConfig:^(XMConfig *config) { config.generalServer = @"general server address"; config.generalHeaders = @{@"general-header": @"general header value"}; config.generalParameters = @{@"general-parameter": @"general parameter value"}; config.generalUserInfo = nil; config.callbackQueue = dispatch_get_main_queue(); #ifdef DEBUG config.consoleLog = YES; #endif }];
你能夠調用 XMCenter
的 +setupConfig:
類方法,經過修改傳入的 XMConfig
對象來配置全局網絡請求的公共信息,包括以下:
server
屬性爲 nil
,且其 useGeneralServer
爲 YES
(默認),那麼該請求的服務端地址 server
將會取 XMCenter 中 generalServer
的值。useGeneralParameters
屬性爲 YES
(默認),而且 XMCenter 的公共參數 generalParameters
不爲空,那麼這些公共參數會自動加到該請求的 parameters
中。useGeneralHeaders
屬性爲 YES
(默認),而且 XMCenter 的公共請求頭 generalHeaders
不爲空,那麼這些公共請求頭會自動加到該請求的 headers
中。nil
,若是一個 XMRequest 請求對象的 userInfo
屬性爲 nil
(默認)而該字段不爲 nil
,那麼該字段會自動賦值給 XMRequest
對象的 userInfo
。而 userInfo
屬性可用於區分具備相同上下文信息的不一樣請求。NULL
(默認),那麼會在一個私有的併發隊列(子線程)中執行回調 Block。BOOL
值,用於表示是否在控制檯輸出請求和響應的信息,默認爲 NO
。另外,你能夠經過調用 XMCenter
的如下兩個類方法來隨時修改全局公共的 header 和 parameter:
+ (void)setGeneralHeaderValue:(nullable NSString *)value forField:(NSString *)field; + (void)setGeneralParameterValue:(nullable NSString *)value forKey:(NSString *)key;
[XMCenter sendRequest:^(XMRequest *request) { request.url = @"http://example.com/v1/foo/bar"; //request.server = @"http://example.com/v1/"; //request.api = @"foo/bar"; request.parameters = @{@"param1": @"value1", @"param2": @"value2"}; request.headers = @{@"User-Agent": @"Custom User Agent"}; request.httpMethod = kXMHTTPMethodGET; } onSuccess:^(id responseObject) { NSLog(@"onSuccess: %@", responseObject); } onFailure:^(NSError *error) { NSLog(@"onFailure: %@", error); } onFinished:^(id responseObject, NSError *error) { NSLog(@"onFinished"); }];
注意1:能夠經過如下兩種方法設置一個請求對象的 URL 地址,但當 server
、api
和 url
三個屬性被同時賦值時,url
的優先級比較高,而此時 server
、api
的值會被忽略。
request.url = @"http://example.com/v1/foo/bar";
// 若是 request.server 爲 `nil`,且 request.useGeneralServer 爲 `YES`,那麼此時 request.server 會取 XMCenter.generalServer 的值。 request.server = @"http://example.com/v1/"; request.api = @"foo/bar";
注意2:一個請求對象的回調 Block (success/failure/finished/progress) 是非必需的(默認爲 nil
),XMCenter 提供了多個設置不一樣回調 Block 參數的方法用於發送請求。另外,須要注意的是,success/faillure/finished 等回調 Block 會在 XMCenter 設置的 callbackQueue
隊列中被執行,但 progress 回調 Block 將在 NSURLSession 本身的隊列中執行,而不是 callbackQueue
。
[XMCenter sendRequest:^(XMRequest *request) { //request.server = @"http://example.com/v1/"; // 可選,若是爲空則讀取 XMCenter.generalServer request.api = @"foo/bar"; request.parameters = @{@"param1": @"value1", @"param2": @"value2"}; request.httpMethod = kXMHTTPMethodPOST; // 可選,默認爲 `POST` request.requestType = kXMRequestNormal; // 可選,默認爲 `Normal` } onSuccess:^(id responseObject) { NSLog(@"onSuccess: %@", responseObject); } onFailure:^(NSError *error) { NSLog(@"onFailure: %@", error); }];
XMRequest 一樣支持其餘 HTTP 方法,好比:HEAD
, DELETE
, PUT
, PATCH
等,使用方式與上述相似,再也不贅述。
詳見 XMConst
、XMRequest
和 XMCenter
等幾個文件中的代碼和註釋。
// `NSData` form data. UIImage *image = [UIImage imageNamed:@"testImage"]; NSData *fileData1 = UIImageJPEGRepresentation(image, 1.0); // `NSURL` form data. NSString *path = [NSHomeDirectory() stringByAppendingString:@"/Documents/testImage.png"]; NSURL *fileURL2 = [NSURL fileURLWithPath:path isDirectory:NO]; [XMCenter sendRequest:^(XMRequest *request) { request.server = @"http://example.com/v1/"; request.api = @"foo/bar"; request.requestType = kXMRequestUpload; [request addFormDataWithName:@"image[]" fileName:@"temp.jpg" mimeType:@"image/jpeg" fileData:fileData1]; [request addFormDataWithName:@"image[]" fileURL:fileURL2]; // see `XMUploadFormData` for more details. } onProgress:^(NSProgress *progress) { // the progress block is running on the session queue. if (progress) { NSLog(@"onProgress: %f", progress.fractionCompleted); } } onSuccess:^(id responseObject) { NSLog(@"onSuccess: %@", responseObject); } onFailure:^(NSError *error) { NSLog(@"onFailure: %@", error); } onFinished:^(id responseObject, NSError *error) { NSLog(@"onFinished"); }];
[XMCenter sendRequest:^(XMRequest *request) { request.url = @"http://example.com/v1/testDownFile.zip"; request.downloadSavePath = [NSHomeDirectory() stringByAppendingString:@"/Documents/"]; request.requestType = kXMRequestDownload; } onProgress:^(NSProgress *progress) { // the progress block is running on the session queue. if (progress) { NSLog(@"onProgress: %f", progress.fractionCompleted); } } onSuccess:^(id responseObject) { NSLog(@"onSuccess: %@", responseObject); } onFailure:^(NSError *error) { NSLog(@"onFailure: %@", error); }];
XMRequest
中有兩個屬性 requestSerializerType
和 responseSerializerType
分別用於設置請求參數和響應結果的序列化類型。
其中,XMRequestSerializerType
和 XMResponseSerializerType
枚舉的定義以下:
typedef NS_ENUM(NSInteger, XMRequestSerializerType) { kXMRequestSerializerRAW = 0, // default kXMRequestSerializerJSON = 1, kXMRequestSerializerPlist = 2, };
typedef NS_ENUM(NSInteger, XMResponseSerializerType) { kXMResponseSerializerRAW = 0, kXMResponseSerializerJSON = 1, // default kXMResponseSerializerPlist = 2, kXMResponseSerializerXML = 3, };
詳見 AFURLRequestSerialization.h
和 AFURLResponseSerialization.h
獲取更多細節。
一般地,一個請求成功結束時,會執行 success block,當有錯誤發生時,執行 failure block。然而,開發中更常見的狀況是,即便是一個請求成功結束,咱們也須要進一步處理,好比驗證響應結果數據、判斷與服務端商量好的業務錯誤碼類型等,再決定執行 success block 仍是 failure block。
如今,你能夠調用 [XMCenter setResponseProcessBlock:...]
方法以 Block 注入的方式設置自定義的處理邏輯,當請求成功結束時,這個 Block 會在 success block 被執行前調用,若是傳入 *error
參數被賦值,則接下來會執行 failure block。
[XMCenter setResponseProcessBlock:^(XMRequest *request, id responseObject, NSError *__autoreleasing *error) { // 自定義響應結果處理邏輯,若是 `*error` 被賦值,則接下來會執行 failure block。 }];
XMNetworking 支持同時發一組批量請求,這組請求在業務邏輯上相關,但請求自己是互相獨立的,success block 會在全部請求都成功結束時才執行,而一旦有一個請求失敗,則會執行 failure block。注:回調 Block 中的 responseObjects
和 errors
中元素的順序與每一個 XMRequest 對象在 batchRequest.requestArray
中的順序一致。
[XMCenter sendBatchRequest:^(XMBatchRequest *batchRequest) { XMRequest *request1 = [XMRequest request]; request1.url = @"server url 1"; // set other properties for request1 XMRequest *request2 = [XMRequest request]; request2.url = @"server url 2"; // set other properties for request2 [batchRequest.requestArray addObject:request1]; [batchRequest.requestArray addObject:request2]; } onSuccess:^(NSArray<id> *responseObjects) { NSLog(@"onSuccess: %@", responseObjects); } onFailure:^(NSArray<id> *errors) { NSLog(@"onFailure: %@", errors); } onFinished:^(NSArray<id> *responseObjects, NSArray<id> *errors) { NSLog(@"onFinished"); }];
[XMCenter sendBatchRequest:...]
方法會返回剛發起的新的 XMBatchRequest
對象,你能夠保存這個對象,並在必要的時候調用它的 -cancelWithBlock:
方法取消這組批量請求。
XMNetworking 一樣支持發一組鏈式請求,這組請求之間互相依賴,下一請求是否發送以及請求的參數取決於上一個請求的結果,success block 會在全部的鏈式請求都成功結束時才執行,而中間一旦有一個請求失敗,則會執行 failure block。注:回調 Block 中的 responseObjects
和 errors
中元素的順序與每一個鏈式請求 XMRequest
對象的前後順序一致。
[XMCenter sendChainRequest:^(XMChainRequest *chainRequest) { [[[[chainRequest onFirst:^(XMRequest *request) { request.url = @"server url 1"; // set other properties for request }] onNext:^(XMRequest *request, id responseObject, BOOL *sendNext) { NSDictionary *params = responseObject; if (params.count > 0) { request.url = @"server url 2"; request.parameters = params; } else { *sendNext = NO; } }] onNext:^(XMRequest *request, id responseObject, BOOL *sendNext) { request.url = @"server url 3"; request.parameters = @{@"param1": @"value1", @"param2": @"value2"}; }] onNext: ...]; } onSuccess:^(NSArray<id> *responseObjects) { NSLog(@"onSuccess: %@", responseObjects); } onFailure:^(NSArray<id> *errors) { NSLog(@"onFailure: %@", errors); } onFinished:^(NSArray<id> *responseObjects, NSArray<id> *errors) { NSLog(@"onFinished"); }];
[XMCenter sendChainRequest:...]
方法會返回剛發起的新的 XMChainRequest
對象,你能夠保存這個對象,並在必要的時候調用它的 -cancelWithBlock:
方法取消這組鏈式請求。
當調用 [XMCenter sendRequest:...]
方法發送一個網絡請求時,該方法會返回一個用於惟一標識該請求對象的 identifier
(若是請求發送失敗,該值爲 0
)。在必要的時候,你能夠經過這個 identifier
來取消當前網絡請求(若是一個請求已經結束,這時再用 identifier
來取消該請求時,會直接忽略)。
// send a request NSUInteger identifier = [XMCenter sendRequest:^(XMRequest *request) { request.server = @"https://kangzubin.cn/"; request.api = @"test/index.php"; request.httpMethod = kXMHTTPMethodGET; request.timeoutInterval = 10; request.retryCount = 1; } onFailure:^(NSError *error) { NSLog(@"onFailure: %@", error); }]; // your business code sleep(2); // cancel the running request by identifier with cancel block [XMCenter cancelRequest:identifier onCancel:^(XMRequest *request) { NSLog(@"onCancel"); }];
注意:調用 XMCenter cancelRequest:onCancel:
方法取消一個網絡請求時,被取消的請求對象(若是存在)會以參數的形式傳給 cancel block,另外 cancel block 是在當前調用 cancelRequest:
方法的線程中執行,並非 XMCenter 的 callbackQueue
。
咱們提供了兩種方法用於獲取網絡的可鏈接性,分別以下:
[XMCenter isNetworkReachable]; // 該方法會返回一個 Bool 值用於表示當前網絡是否可鏈接。
[[XMEngine sharedEngine] networkReachability]; // 該方法會返回一個當前網絡的狀態值,-1 表示 `Unknown`,0 表示 `NotReachable,1 表示 `WWAN`,2 表示 `WiFi`
詳見 AFNetworkReachabilityManager
獲取更多細節.
在你的應用程序包裏添加 (pinned) 相應的 SSL 證書作校驗有助於防止中間人攻擊和其餘安全漏洞。很是方便的是,AFNetworking 的 AFSecurityPolicy
安全模塊能夠經過校驗本地保存的證書或公鑰幫助咱們評估服務器是否可信任以及創建安全鏈接。
咱們在 XMEngine
中暴露了一個 AFHTTPSessionManager
對象叫 sessionManager
,你能夠經過修改該對象的 securityPolicy
類型,以開啓 SSL Pinning 功能,並把大家服務器對應的 .cer
證書或者公鑰放到你的工程中。
[XMEngine sharedEngine].sessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
詳見 AFSecurityPolicy
獲取更多細節.
詳見 XMNetworking Documents Link.
XMNetworking 的代碼結構很是簡潔和緊湊,只包含了 4 個核心文件:XMConst.h
用於定義全局常量枚舉和 Block,XMRequest
,XMCenter
和 XMEngine
則是核心類的聲明和實現,具體的代碼結構以下圖所示:
Architecture.png
XMNetworking 使用 MIT 許可證,詳情見 LICENSE 文件。
文/XcodeMen(簡書做者) 原文連接:http://www.jianshu.com/p/a5c5e9aa5913