這段時間要將公司項目中的網絡引擎由ASIHTTPRequest替換為AFNetworking,替換的過程比較曲折,在此記錄下自己替換過程中得心得:
1、建立數據請求中介者
建立中介者
是指項目中的數據請求都通過它去實現,而不是每一個數據請求都直接與AFNetworking
打交道,這樣做的好處是:
- 將網絡請求與第三方庫依賴隔離開來,方便以后對第三方庫的替換。
- 方便處理網絡請求的公共邏輯。
2、使用completionQueue
默認情況下AFURLConnectionOperation
或者AFHTTPRequestOperation
請求結束以后會在主線程將結果傳遞回來,如果你要將請求的結果做一些耗時的復雜的處理,就會block住主線程,所以這種情況下你就需要對請求的Operation傳遞completionQueue
參數:
AFHTTPRequestOperation *request = [[AFHTTPRequestOperation alloc] initWithRequest:urlrequest];
request.responseSerializer = [AFJSONResponseSerializer serializer];
//設置回調的queue,默認是在mainQueue執行block回調
request.completionQueue = your_request_operation_completion_queue();
[request setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
//設置了'completionQueue'后,就可以在這里處理復雜的邏輯
//不用擔心block住了主線程
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[request start];
3、如何知道AFHTTPRequestOperationManager執行完成
開始以為直接設置AFHTTPRequestOperationManager
的completionGroup,然后利用dispatch_group_notify
來獲取operationQueue執行結束的通知,最后才發現,這樣根本不行,看了源碼才知道:AFHTTPRequestOperationManager
直接將completionGroup賦值給了他的每一個operation,在operation的completionBlock里面利用completionGroup,來確保在operation的處理完成后,將completionBlock置為nil,防止循環引用。
雖然說這樣不能知道AFHTTPRequestOperationManager
什么時候執行完成,但是生活還得繼續下去??!在AFURLConnectionOperation
中有一個方法叫:
+ (NSArray *)batchOfRequestOperations:(NSArray *)operations
progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
completionBlock:(void (^)(NSArray *operations))completionBlock;
這個方法就是能夠發一組請求,跟AFHTTPRequestOperationManager
比起來的缺點就是沒法設置并發數,但是它卻能實現檢測一組請求什么時候結束,能檢測完成了多少請求,它是怎么做到的呢?
原來他也是利用dispatch_group_async和dispatch_group_notify
一般的我們要把一個任務加入一個group里是這樣:
dispatch_group_async(group, queue, ^{
block();
});
這個寫法等價于
dispatch_async(queue, ^{
dispatch_group_enter(group);
block()
dispatch_group_leave(group);
});
如果要把一個異步任務加入group,這樣就行不通了:
dispatch_group_async(group, queue, ^{
[self performBlock:^(){
block();
}];
//未執行到block() group任務就已經完成了
});
這是就需要用到batchOfRequestOperations
里的實現了:
dispatch_group_enter(group);
[self performBlock:^(){
block();
dispatch_group_leave(group);
}];
其實這個和引用計數差不多,dispatch_group_enter時引用計數+1,dispatch_group_leave時引用計數-1,引用計數為0時執行dispatch_group_notify的內容。具體過程大致如下:
AFHTTPRequestOperationManager *downloadManager = [AFHTTPRequestOperationManager manager];
//設置最大并發數
[downloadManager.operationQueue setMaxConcurrentOperationCount:([NSProcessInfo processInfo].processorCount) * 2];
//創建一個group
__block dispatch_group_t group = dispatch_group_create();
for (NSURL *url in urlArray) {
NSURLRequest *requestUrl = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:requestUrl];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
dispatch_group_leave(group);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
dispatch_group_leave(group);
}];
//將請求加入隊列中
[downloadManager.operationQueue addOperation:requestOperation];
dispatch_group_enter(group);
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//全部請求完成
});
4、實現斷點續傳
AFNetworking
雖然支持文件下載的暫停和繼續,但是當緩存清空重新啟動時,它并沒有記錄下下載的狀態,無法續傳,但是可以通過AFDownloadRequestOperation來簡單的實現,其實過程也不是很復雜,大致如下,感興趣的朋友可以閱讀AFDownloadRequestOperation
是實現部分:
1、設置AFHTTPRequestOperation
的請求NSMutableURLRequest
HTTPHeader的Range字段。
NSMutableURLRequest *mutableURLRequest = [self.request mutableCopy];
//offset是指斷點續傳文件已經下載的大小
[mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"];
2、設置AFHTTPRequestOperation
的outputStream屬性。
//downloadPath是指文件下載存放的路徑
downloadOperation.outputStream = [NSOutputStream outputStreamToFileAtPath:downloadPath append:YES];
結尾
對于ASIHTTPRequest
和AFNetworking
的比較網上有很多很好的文章,一搜一大把,對于普通的使用來說感覺區別不大,請求速度什么的也沒什么感覺,以上若有錯誤,還望大家多多
指正??。