一個編寫iOS程式碼的經典場景:使用者進入某個Controller,發起Http網路請求從Server獲取資料,在資料返回之前使用者退出了Controller。此時是否需要Cancel之前發出的網路請求呢?
如果請求的資料只在當前Controller產生內容,結論當然是需要Cancel,雖然我知道不少iOS程式設計師因為偷懶而忘了取消。我們用工程的思維,深入本質,一起看下這背後都發生了什麼,如果不Cancel會有哪些副作用。
我們可以把一個Http請求分為這幾步:
第一步:三次握手
這一步會有三個packet產生,sync,sync+ack,ack。
第二步:客戶端傳送Http的request
此處根據請求型別產生的packet數量會有差異。
第三步:客戶端接收Server的Http Response
根據Response的大小,產生的packet數量不相同,一般一個packet在1.5KB左右。
通過程式碼檢視測試樣本
我們在Demo專案中執行如下程式碼,再配合tcpdump抓包看看背後究竟發生了什麼?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; NSURL *URL = [NSURL URLWithString:@"http://httpbin.org/get"]; NSURLRequest *request = [NSURLRequest requestWithURL:URL]; NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { if (error) { NSLog(@"Error: %@", error); } else { NSLog(@"%@ %@", response, responseObject); } }]; [dataTask resume]; |
1 2 |
sudo tcpdump -i rvi0 -AAlnn src 23.22.14.18 or dst 23.22.14.18 |
下圖是tcpdump獲取的結果:
- 圖中標號1,2,3表示的tcp三次握手。
- 標號4是客戶端傳送Http Get,標號5是Server Ack。
- 標號6是Server Response。
後面還有幾個斷開tcp連線的包被我省去了,前面這6個packet足以說明問題了。
上述三步中,前兩步消耗的是使用者上行的流量,第三步用的下行的流量。國內移動運營商對於上行和下行的流量都算在包月的總流量當中的,所以如果使用者在第六個或者之後的Packet沒有返回之前退出Controller的話,後續的Packet依然會通過連線,走下行通道,抵達我們的客戶端,耗費使用者的流量,Response往往還是一個請求的流量大頭。
如果我們在請求返回之前,呼叫Cancel:
1 2 |
[dataTask cancel]; |
取消請求的話,客戶端會傳送如下一個Reset Packet斷開當前的Http連線,阻止後續的流量產生:
所以結論是:如果不Cancel,請求完成之後通過回撥找到delegate,如果是weak引用,Controller被釋放,delegate變為nil,業務流程被中斷,程式碼還算安全。但是會的的確確浪費一些使用者流量。養成好習慣,自己產生的垃圾自己清理哦。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!