在蘋(píng)果徹底棄用NSURLConnection之后自己總結(jié)的一個(gè)網(wǎng)上的內(nèi)容,加上自己寫(xiě)的小Demo所刀,很多都是借鑒網(wǎng)絡(luò)上的資源仰泻,有需要的朋友可以看看。
排版之前也是亂弄的(因?yàn)橹熬妥约嚎疵磭澹?br>
可以看Demo下的pdf
Demo地址:https://github.com/Fuhanyu/FHYNSURLSessionDemo
一.引言:
由于Xcode 7中篮愉,NSURLConnection的API已經(jīng)正式被蘋(píng)果棄用腐芍。雖然該API將繼續(xù)運(yùn)行,但將沒(méi)有新功能將被添加试躏,并且蘋(píng)果已經(jīng)通知所有基于網(wǎng)絡(luò)的功能猪勇,以充分使NSURLSession向前發(fā)展。
二.快速了解與改變AFNetworking篇:
AFNetworking是一款在OS X和iOS下都令人喜愛(ài)的網(wǎng)絡(luò)庫(kù),為了迎合iOS新版本的升級(jí), AFNetworking在3.0版本中刪除了基于 NSURLConnection API的所有支持颠蕴。如果你的項(xiàng)目以前使用過(guò)這些API泣刹,建議您立即升級(jí)到基于 NSURLSession 的API的AFNetworking的版本。
AFNetworking 1.0建立在NSURLConnection的基礎(chǔ)API之上 犀被,AFNetworking 2.0開(kāi)始使用NSURLConnection的基礎(chǔ)API 椅您,以及較新基于NSURLSession的API的選項(xiàng)寡键。 AFNetworking 3.0現(xiàn)已完全基于NSURLSession的API,這降低了維護(hù)的負(fù)擔(dān)开伏,同時(shí)支持蘋(píng)果增強(qiáng)關(guān)于NSURLSession提供的任何額外功能遭商。
1.棄用的類
下面的類已從AFNetworking 3.0中廢棄:
- AFURLConnectionOperation
- AFHTTPRequestOperation
- AFHTTPRequestOperationManager
2.讓我們看一下原來(lái)封裝的簡(jiǎn)單網(wǎng)絡(luò)處理類
//創(chuàng)建一個(gè)HTTP請(qǐng)求操作管理對(duì)象
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
//通過(guò)設(shè)置responseSerializer,自動(dòng)完成返回?cái)?shù)據(jù)的解析劫流,直接獲取json格式的responseObject巫玻。
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json", @"text/plain", @"text/html", nil];
//允許無(wú)效的 SSL 證書(shū):
//NSURLConnection已經(jīng)封裝了https連接的建立丛忆、數(shù)據(jù)的加密解密功能,我們直接使用NSURLConnection是可以訪問(wèn)https網(wǎng)站的仍秤,但NSURLConnection并沒(méi)有驗(yàn)證證書(shū)是否合法熄诡,無(wú)法避免中間人攻擊。要做到真正安全通訊诗力,需要我們手動(dòng)去驗(yàn)證服務(wù)端返回的證書(shū)凰浮,AFSecurityPolicy封裝了證書(shū)驗(yàn)證的過(guò)程,讓用戶可以輕易使用苇本,除了去系統(tǒng)信任CA機(jī)構(gòu)列表驗(yàn)證袜茧,還支持SSL Pinning方式的驗(yàn)證。
manager.securityPolicy.allowInvalidCertificates = YES;//生產(chǎn)環(huán)境不建議使用
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"%@",responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"%@",error);
}];
3.AFHTTPRequestOperationManager 核心代碼
如果你以前使用 AFHTTPRequestOperationManager 瓣窄, 你將需要遷移去使用AFHTTPSessionManager笛厦。 以下的類在兩者過(guò)渡間并沒(méi)有變化:
- securityPolicy 安全政策
- requestSerializer 請(qǐng)求串行器
- responseSerializer 響應(yīng)串行器
AFNetworking 2.x
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:@"請(qǐng)求的url" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"成功");
} failure:^(AFHTTPRequestOperation operation, NSErrorerror) {
NSLog(@"失敗");
}];
AFNetworking 3.0
AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
[session GET:@"請(qǐng)求的url" parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"成功");
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"失敗");
}];
三.基本了解NSURLSession
1.了解Apple 的網(wǎng)絡(luò)連接API
NSURLConnection 作為 Core Foundation / CFNetwork 框架的 API 之上的一個(gè)抽象,在 2003 年俺夕,隨著第一版的 Safari 的發(fā)布就發(fā)布了裳凸。NSURLConnection 這個(gè)名字,實(shí)際上是指代的 Foundation 框架的 URL 加載系統(tǒng)中一系列有關(guān)聯(lián)的組件:NSURLRequest劝贸、NSURLResponse姨谷、NSURLProtocol、 NSURLCache悬荣、NSHTTPCookieStorage菠秒、NSURLCredentialStorage 以及同名類 NSURLConnection疙剑。
NSURLRequest 被傳遞給 NSURLConnection。被委托對(duì)象(遵守以前的非正式協(xié)議 <NSURLConnectionDelegate> 和<NSURLConnectionDataDelegate>)異步地返回一個(gè) NSURLResponse 以及包含服務(wù)器返回信息的 NSData嚼蚀。
NSURLConnection 作為網(wǎng)絡(luò)基礎(chǔ)架構(gòu),已經(jīng)服務(wù)了成千上萬(wàn)的 iOS 和 Mac OS 程序导帝,并且做的還算相當(dāng)不錯(cuò)。但是這些年虐秦,一些用例——尤其是在 iPhone 和 iPad 上面——已經(jīng)對(duì) NSURLConnection 的幾個(gè)核心概念提出了挑戰(zhàn)蜈彼,讓蘋(píng)果有理由對(duì)它進(jìn)行重構(gòu)幸逆。
在 2013 的 WWDC 上,蘋(píng)果推出了 NSURLConnection 的繼任者:NSURLSession蚕甥。
和 NSURLConnection 一樣,NSURLSession 指的也不僅是同名類 NSURLSession爱沟,還包括一系列相互關(guān)聯(lián)的類。NSURLSession 包括了與之前相同的組件括享,NSURLRequest 與 NSURLCache铃辖,但是把 NSURLConnection 替換成了NSURLSession、NSURLSessionConfiguration 以及 NSURLSessionTask 的 3 個(gè)子類:NSURLSessionDataTask犬第,NSURLSessionUploadTask,NSURLSessionDownloadTask遥椿。
與 NSURLConnection 相比家浇,NSURLsession 最直接的改進(jìn)就是可以配置每個(gè) session 的緩存,協(xié)議莺琳,cookie惭等,以及證書(shū)策略(credential policy),甚至跨程序共享這些信息秤茅。這將允許程序和網(wǎng)絡(luò)基礎(chǔ)框架之間相互獨(dú)立框喳,不會(huì)發(fā)生干擾。每個(gè)NSURLSession 對(duì)象都由一個(gè) NSURLSessionConfiguration 對(duì)象來(lái)進(jìn)行初始化拼余,后者指定了剛才提到的那些策略以及一些用來(lái)增強(qiáng)移動(dòng)設(shè)備上性能的新選項(xiàng)凡橱。
NSURLSession 中另一大塊就是 session task稼钩。它負(fù)責(zé)處理數(shù)據(jù)的加載以及文件和數(shù)據(jù)在客戶端與服務(wù)端之間的上傳和下載静秆。NSURLSessionTask 與 NSURLConnection 最大的相似之處在于它也負(fù)責(zé)數(shù)據(jù)的加載扶认,最大的不同之處在于所有的 task 共享其創(chuàng)造者 NSURLSession 這一公共委托者(common delegate)辐宾。
NSURLSessionTask
NSURLsessionTask 是一個(gè)抽象類,其下有 3 個(gè)實(shí)體子類可以直接使用:NSURLSessionDataTask誉察、NSURLSessionUploadTask、NSURLSessionDownloadTask综液。這 3 個(gè)子類封裝了現(xiàn)代程序三個(gè)最基本的網(wǎng)絡(luò)任務(wù):獲取數(shù)據(jù)谬莹,比如 JSON 或者 XML,上傳文件和下載文件蕉扮。
當(dāng)一個(gè) NSURLSessionDataTask 完成時(shí),它會(huì)帶有相關(guān)聯(lián)的數(shù)據(jù)奔则,而一個(gè) NSURLSessionDownloadTask 任務(wù)結(jié)束時(shí),它會(huì)帶回已下載文件的一個(gè)臨時(shí)的文件路徑抽莱。因?yàn)橐话銇?lái)說(shuō)匕垫,服務(wù)端對(duì)于一個(gè)上傳任務(wù)的響應(yīng)也會(huì)有相關(guān)數(shù)據(jù)返回年缎,所以NSURLSessionUploadTask 繼承自 NSURLSessionDataTask。
所有的 task 都是可以取消犁柜,暫桶峭螅或者恢復(fù)的。當(dāng)一個(gè) download task 取消時(shí)蹋盆,可以通過(guò)選項(xiàng)來(lái)創(chuàng)建一個(gè)恢復(fù)數(shù)據(jù)(resume data),然后可以傳遞給下一次新創(chuàng)建的 download task析藕,以便繼續(xù)之前的下載。
1??NSURLSessionDataTask
2.GET請(qǐng)求
//1.創(chuàng)建NSURLSession對(duì)象(可以獲取單例對(duì)象)
NSURLSession *session = [NSURLSession sharedSession];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://api.liwushuo.com/v2/banners?channel=iOS"]];
//2.根據(jù)NSURLSession對(duì)象創(chuàng)建一個(gè)Task
/*
注意:該block是在子線程中調(diào)用的,如果拿到數(shù)據(jù)之后要做一些UI刷新操作,那么需要回到主線程刷新
第一個(gè)參數(shù):需要發(fā)送的請(qǐng)求對(duì)象
block:當(dāng)請(qǐng)求結(jié)束拿到服務(wù)器響應(yīng)的數(shù)據(jù)時(shí)調(diào)用block
block-NSData:該請(qǐng)求的響應(yīng)體
block-NSURLResponse:存放本次請(qǐng)求的響應(yīng)信息仑鸥,響應(yīng)頭意狠,真實(shí)類型為NSHTTPURLResponse
block-NSErroe:請(qǐng)求錯(cuò)誤信息
*/
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//拿到響應(yīng)頭信息
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
//4.解析拿到的響應(yīng)數(shù)據(jù)
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
NSLog(@"%@ \n %@", dic, res.allHeaderFields);
}];
//3.執(zhí)行Task
//注意:剛創(chuàng)建出來(lái)的task默認(rèn)是掛起狀態(tài)的澎灸,需要調(diào)用該方法來(lái)啟動(dòng)任務(wù)(執(zhí)行任務(wù)
[dataTask resume];
3.第二種GET請(qǐng)求
//1.創(chuàng)建NSURLSession對(duì)象(可以獲取單例對(duì)象)
NSURLSession session = [NSURLSession sharedSession];
//2.創(chuàng)建一個(gè)Task
//注意:該方法內(nèi)部默認(rèn)會(huì)把URL對(duì)象包裝成一個(gè)NSURLRequest對(duì)象(默認(rèn)是GET請(qǐng)求)
//方法參數(shù)說(shuō)明
/
//第一個(gè)參數(shù):發(fā)送請(qǐng)求的URL地址
//block:當(dāng)請(qǐng)求結(jié)束拿到服務(wù)器響應(yīng)的數(shù)據(jù)時(shí)調(diào)用block
//block-NSData:該請(qǐng)求的響應(yīng)體
//block-NSURLResponse:存放本次請(qǐng)求的響應(yīng)信息拦止,響應(yīng)頭其兴,真實(shí)類型為NSHTTPURLResponse
//block-NSErroe:請(qǐng)求錯(cuò)誤信息
*/
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:@"http://api.liwushuo.com/v2/banners?channel=iOS"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//拿到響應(yīng)頭信息
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
//4.解析拿到的響應(yīng)數(shù)據(jù)
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
NSLog(@"%@ \n %@", dic, res.allHeaderFields);
}];
[dataTask resume];
4.POST請(qǐng)求
//1.創(chuàng)建NSURLSession對(duì)象(可以獲取單例對(duì)象)
NSURLSession *session = [NSURLSession sharedSession];
//2.根據(jù)NSURLSession對(duì)象創(chuàng)建一個(gè)Task
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
//創(chuàng)建一個(gè)請(qǐng)求對(duì)象顶瞒,并這是請(qǐng)求方法為POST,把參數(shù)放在請(qǐng)求體中傳遞
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {
//拿到響應(yīng)頭信息
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
//解析拿到的響應(yīng)數(shù)據(jù)
NSLog(@"%@\n%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],res.allHeaderFields);
}];
//3.執(zhí)行Task
//注意:剛創(chuàng)建出來(lái)的task默認(rèn)是掛起狀態(tài)的元旬,需要調(diào)用該方法來(lái)啟動(dòng)任務(wù)(執(zhí)行任務(wù))
[dataTask resume];
2??NSURLSessionDownloadTask
1.使用NSURLSession和NSURLSessionDownload可以很方便的實(shí)現(xiàn)文件下載操作
//
// NSURLSessionNetWork.m
// FHYNetworkHandle
//
// Created by 付寒宇 on 15/11/7.
// Copyright ? 2015年 付寒宇. All rights reserved.
//
import "NSURLSessionDownloadTaskShow.h"
@interface NSURLSessionDownloadTaskShow ()<NSURLSessionDownloadDelegate>
@property (strong, nonatomic) IBOutlet UIImageView *imageView;
@property (strong, nonatomic) IBOutlet UIProgressView *progressBar;
@property (strong, nonatomic) IBOutlet UIButton *start;
@property (strong, nonatomic) IBOutlet UIButton *pause;
@property (strong, nonatomic) IBOutlet UIButton *resume;
@property (atomic, strong) NSURLSessionDownloadTask *task;
@property (atomic, strong) NSData *partialData;
@end
@implementation NSURLSessionDownloadTaskShow
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"NSURLSessionDownloadTask";
}
//創(chuàng)建Session對(duì)象
(NSURLSession *)createASession{
//創(chuàng)建NSURLSession配置對(duì)象Configuration
NSURLSessionConfiguration configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
//創(chuàng)建NSURLSession,并設(shè)置代理
/
第一個(gè)參數(shù):session對(duì)象的全局配置設(shè)置榴徐,一般使用默認(rèn)配置就可以
第二個(gè)參數(shù):誰(shuí)成為session對(duì)象的代理
第三個(gè)參數(shù):代理方法在哪個(gè)隊(duì)列中執(zhí)行(在哪個(gè)線程中調(diào)用),如果是主隊(duì)列那么在主線程中執(zhí)行,如果是非主隊(duì)列法绵,那么在子線程中執(zhí)行
*/
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
return session;
}
//創(chuàng)建Session請(qǐng)求(NSURLRequest *)createARequest{
//注意:如果要發(fā)送POST請(qǐng)求箕速,那么請(qǐng)?jiān)O(shè)置一些請(qǐng)求頭信息
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://p1.pichost.me/i/40/1639665.png"]];
return request;
}
//開(kāi)始下載-
(IBAction)start:(id)sender {
//用NSURLSession和NSURLRequest創(chuàng)建網(wǎng)絡(luò)任務(wù)self.task = [[self createASession] downloadTaskWithRequest:[self createARequest]];
[self.task resume];
}
//暫停下載 (IBAction)pause:(id)sender {
NSLog(@"Pause download task");
if (self.task) {
//取消下載任務(wù),把已下載數(shù)據(jù)存起來(lái)
//如果采取這種方式來(lái)取消任務(wù),那么該方法會(huì)通過(guò)resumeData保存當(dāng)前文件的下載信息
//只要有了這份信息常柄,以后就可以通過(guò)這些信息來(lái)恢復(fù)下載
[self.task cancelByProducingResumeData:^(NSData *resumeData) {
self.partialData = resumeData;
self.task = nil;
}];
}
}
//繼續(xù)開(kāi)始(IBAction)resume:(id)sender {
NSLog(@"resume download task");
if (!self.task) {
//判斷是否又已下載數(shù)據(jù),有的話就斷點(diǎn)續(xù)傳腹备,沒(méi)有就完全重新下載
if (self.partialData) {
//繼續(xù)下載
//首先通過(guò)之前保存的resumeData信息,創(chuàng)建一個(gè)下載任務(wù)
self.task = [[self createASession] downloadTaskWithResumeData:self.partialData];
}else{
self.task = [[self createASession] downloadTaskWithRequest:[self createARequest]];
}
}
[self.task resume];
}
pragma mark NSURLSessionDownloadDelegate
//完成下載任務(wù) 保存
-
(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
//下載成功后买喧,文件是保存在一個(gè)臨時(shí)目錄的蔗蹋,需要開(kāi)發(fā)者自己考到放置該文件的目錄
NSLog(@"Download success for URL: %@",location.description);
NSURL *destination = [self createDirectoryForDownloadItemFromURL:location];
BOOL success = [self copyTempFileAtURL:location toDestination:destination];if(success){
// 文件保存成功后,使用GCD調(diào)用主線程把圖片文件顯示在UIImageView中
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithContentsOfFile:[destination path]];
self.imageView.image = image;
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
self.imageView.hidden = NO;
});
}else{
NSLog(@"Meet error when copy file");
}
self.task = nil;
}
//返回下載進(jìn)度代理方法
/*
當(dāng)接收到下載數(shù)據(jù)的時(shí)候調(diào)用,可以在該方法中監(jiān)聽(tīng)文件下載的進(jìn)度
該方法會(huì)被調(diào)用多次
totalBytesWritten:已經(jīng)寫(xiě)入到文件中的數(shù)據(jù)大小
totalBytesExpectedToWrite:目前文件的總大小
bytesWritten:本次下載的文件數(shù)據(jù)大小
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
//刷新進(jìn)度條的delegate方法,同樣的周霉,獲取數(shù)據(jù)跟衅,調(diào)用主線程刷新UI
double currentProgress = totalBytesWritten/(double)totalBytesExpectedToWrite;
dispatch_async(dispatch_get_main_queue(), ^{
self.progressBar.progress = currentProgress;
self.progressBar.hidden = NO;
});
}
//創(chuàng)建文件本地保存目錄
-(NSURL *)createDirectoryForDownloadItemFromURL:(NSURL *)location
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *urls = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *documentsDirectory = urls[0];
return [documentsDirectory URLByAppendingPathComponent:[location lastPathComponent]];
}
//把文件拷貝到指定路徑
-(BOOL) copyTempFileAtURL:(NSURL *)location toDestination:(NSURL *)destination
{
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:destination error:NULL];
[fileManager copyItemAtURL:location toURL:destination error:&error];
if (error == nil) {
return true;
}else{
NSLog(@"%@",error);
return false;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
2.downloadTaskWithURL內(nèi)部默認(rèn)已經(jīng)實(shí)現(xiàn)了變下載邊寫(xiě)入操作抵皱,所以不用開(kāi)發(fā)人員擔(dān)心內(nèi)存問(wèn)題
3.文件下載后默認(rèn)保存在tmp文件目錄据途,需要開(kāi)發(fā)人員手動(dòng)的剪切到合適的沙盒目錄
3??NSURLSessionDownloadTask實(shí)現(xiàn)大文件離線斷點(diǎn)下載(完整)
- 1.關(guān)于NSOutputStream的使用
//1. 創(chuàng)建一個(gè)輸入流,數(shù)據(jù)追加到文件的屁股上
//把數(shù)據(jù)寫(xiě)入到指定的文件地址,如果當(dāng)前文件不存在,則會(huì)自動(dòng)創(chuàng)建
NSOutputStream *stream = [[NSOutputStream alloc]initWithURL:[NSURL fileURLWithPath:[self fullPath]] append:YES];
//2. 打開(kāi)流
[stream open];
//3. 寫(xiě)入流數(shù)據(jù)
[stream write:data.bytes maxLength:data.length];
//4.當(dāng)不需要的時(shí)候應(yīng)該關(guān)閉流
[stream close];
2.關(guān)于網(wǎng)絡(luò)請(qǐng)求請(qǐng)求頭的設(shè)置(可以設(shè)置請(qǐng)求下載文件的某一部分)
//1. 設(shè)置請(qǐng)求對(duì)象
//1.1 創(chuàng)建請(qǐng)求路徑
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
//1.2 創(chuàng)建可變請(qǐng)求對(duì)象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//1.3 拿到當(dāng)前文件的殘留數(shù)據(jù)大小
self.currentContentLength = [self FileSize];
//1.4 告訴服務(wù)器從哪個(gè)地方開(kāi)始下載文件數(shù)據(jù)
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentContentLength];
NSLog(@"%@",range);
//1.5 設(shè)置請(qǐng)求
[request setValue:range forHTTPHeaderField:@"Range"];
3.NSURLSession對(duì)象的釋放
-(void)dealloc
{
//在最后的時(shí)候應(yīng)該把session釋放,以免造成內(nèi)存泄露
// NSURLSession設(shè)置過(guò)代理后,需要在最后(比如控制器銷毀的時(shí)候)調(diào)用session的invalidateAndCancel或者resetWithCompletionHandler底桂,才不會(huì)有內(nèi)存泄露
// [self.session invalidateAndCancel];
[self.session resetWithCompletionHandler:^{
NSLog(@"釋放---");
}];
}
4??NSURLSession實(shí)現(xiàn)文件上傳
-
(IBAction)upload:(id)sender {
NSURLSession *session = [NSURLSession sharedSession];/*
第一個(gè)參數(shù):請(qǐng)求對(duì)象
第二個(gè)參數(shù):請(qǐng)求體(要上傳的文件數(shù)據(jù))
block回調(diào):
NSData:響應(yīng)體
NSURLResponse:響應(yīng)頭
NSError:請(qǐng)求的錯(cuò)誤信息
*/
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"我沒(méi)有一個(gè)上傳的網(wǎng)址TAT"]];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:[NSData data] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {}];
[uploadTask resume];
}
/*
調(diào)用該方法上傳文件數(shù)據(jù)
如果文件數(shù)據(jù)很大洞就,那么該方法會(huì)被調(diào)用多次
參數(shù)說(shuō)明:
totalBytesSent:已經(jīng)上傳的文件數(shù)據(jù)的大小
totalBytesExpectedToSend:文件的總大小
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
NSLog(@"%.2f",1.0 * totalBytesSent/totalBytesExpectedToSend);
}
關(guān)于NSURLSessionConfiguration相關(guān)
01 作用:可以統(tǒng)一配置NSURLSession,如請(qǐng)求超時(shí)等
02 創(chuàng)建的方式和使用
//創(chuàng)建配置的三種方式
- (NSURLSessionConfiguration *)defaultSessionConfiguration;
- (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
- (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0);
//統(tǒng)一配置NSURLSession
-(NSURLSession *)session
{
if (_session == nil) {
//創(chuàng)建NSURLSessionConfiguration
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
//設(shè)置請(qǐng)求超時(shí)為10秒鐘
config.timeoutIntervalForRequest = 10;
//在蜂窩網(wǎng)絡(luò)情況下是否繼續(xù)請(qǐng)求(上傳或下載)
config.allowsCellularAccess = NO;
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
return _session;
}
四.使用AFNetworking來(lái)實(shí)現(xiàn)NSURLSession網(wǎng)絡(luò)連接
//
// AFNViewController.m
// FHYNetworkHandle
//
// Created by 付寒宇 on 15/11/7.
// Copyright ? 2015年 付寒宇. All rights reserved.
//
import "AFNViewController.h"
import "FHYNetWork.h"
@interface AFNViewController ()
@property (strong, nonatomic) IBOutlet UIImageView *imageView;
@property (strong, nonatomic) IBOutlet UIProgressView *progressView;
@property (nonatomic, strong) AFURLSessionManager *manager;
@property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;
@property (nonatomic, strong) NSData *partialData;
@end
@implementation AFNViewController
(void)viewDidLoad {
[super viewDidLoad];
[FHYNetWork startMonitoringNetworkStatus];
self.title = [NSString stringWithFormat:@"%ld",[FHYNetWork networkReachabilityStatus]];
// Do any additional setup after loading the view.
}(IBAction)get:(id)sender {
[FHYNetWork handleGETWithUrlString:@"http://api.liwushuo.com/v2/banners?channel=iOS" parameters:nil
showHuD:YES onView:self.imageView successfulBlock:^(id responseObject) {
NSLog(@"%@",responseObject);
} failureBlock:^(NSError *error) {
NSLog(@"fail");
}];
}(IBAction)post:(id)sender {
//http://api2.pianke.me/read/columns?auth=&client=1&deviceid=BA920378-52B5-43F2-BE1A-5404120EDD7A&version=3.0.6
NSDictionary *parameter = @{@"app_installtime":@"1444803219.182004", @"app_versions":@"4.2.2", @"channel_name":@"appStore", @"client_id":@"bt_app_ios", @"client_secret":@"9c1e6634ce1c5098e056628cd66a17a5", @"device_token":@"e7463e1072e3457122562effbab389502ce45dafccc1b05423429470873200ba", @"oauth_token":@"b5718c6bca162f4160ddf992e4a34436", @"os_versions":@"8.3", @"page":@"0", @"pagesize":@"20", @"screensize":@"640", @"show_product":@"1", @"tag_ids":@"5701,6126,757,3153", @"track_device_info":@"iPad4%2C4", @"track_deviceid":@"643DBAC3-6A76-4A19-BFC6-0BCABEE81955", @"track_user_id":@"1394370", @"type_id":@"0", @"v":@"7"};
[FHYNetWork handlePOSTWithUrlString:@"http://open3.bantangapp.com/community/post/listByTags" parameters:parameter showHuD:YES onView:self.view successfulBlock:^(id responseObject) {
NSLog(@"%@",responseObject);
} failureBlock:^(NSError *error) {
NSLog(@"failure");
}];
}-
(IBAction)upload:(id)sender {
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileURL:[NSURL fileURLWithPath:@"file://path/to/image.jpg"] name:@"file" fileName:@"filename.jpg" mimeType:@"image/jpeg" error:nil];
} error:nil];AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSProgress *progress = nil;NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"%@ %@", response, responseObject);
}
}];
[uploadTask resume];
} -
(IBAction)start:(id)sender {
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
self.manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
[_manager setDownloadTaskDidWriteDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDownloadTask * _Nonnull downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
//刷新進(jìn)度條的delegate方法,同樣的范舀,獲取數(shù)據(jù)础爬,調(diào)用主線程刷新UI
double currentProgress = totalBytesWritten/(double)totalBytesExpectedToWrite;
dispatch_async(dispatch_get_main_queue(), ^{
self.progressView.progress = currentProgress;
self.progressView.hidden = NO;
});
}];
NSURL *URL = [NSURL URLWithString:@"http://p1.pichost.me/i/40/1639665.png"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];self.downloadTask = [_manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { NSLog(@"File downloaded to: %@", filePath);
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:filePath]];
[self.imageView setImage:image];}];
[_downloadTask resume];
} (IBAction)pause:(id)sender {
if (_downloadTask) {
[self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
self.partialData = resumeData;
self.downloadTask = nil;
}];
}
}-
(IBAction)resume:(id)sender {
if (!self.downloadTask) {
//判斷是否又已下載數(shù)據(jù)甫贯,有的話就斷點(diǎn)續(xù)傳,沒(méi)有就完全重新下載
if (self.partialData) {self.downloadTask = [_manager downloadTaskWithResumeData:_partialData progress:nil destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) { NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil]; return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]]; } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { NSLog(@"File downloaded to: %@", filePath); UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:filePath]]; [self.imageView setImage:image]; }]; }else{ [self start:nil]; }
}
[self.downloadTask resume];
}
五.封裝NSURLSession網(wǎng)絡(luò)連接
ps:參考連接以及推薦閱讀
原文:From NSURLConnection to NSURLSession https://www.objc.io/issues/5-ios7/from-nsurlconnection-to-nsurlsession/
譯文:從 NSURLConnection 到 NSURLSession http://objccn.io/issue-5-4/
原文:AFNetworking 3.0 Migration Guide https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-3.0-Migration-Guide
譯文:AFNetworking 3.0遷移指南 http://www.reibang.com/p/047463a7ce9b
end