簡介
NSURLSession是蘋果官方提供的一系列網絡接口庫,使用他們可以輕鬆實現下載和數據獲取等任務。在上一篇文章中,我們介紹了使用NSURLConnection下載文件和斷點續傳的功能,實現起來比較麻煩,對於文件的操作也比較繁瑣,如果使用NSURLSession,這一切都將變得極爲容易。
用法
數據請求
1.獲取URLSession單例對象,並利用該對象創建一個dataTask,使用結構體回調。
這段代碼從網站上抓取JSON數組,解析爲OC字典。NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"http://www.soulghost.com/randompk/storeTest/baseRandom.php?type=attack"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; NSLog(@"%@",dict); }];
2.開啓任務
所有任務在創建時都是暫停的,應該手動啓動。[task resume];
小文件下載
1.獲取URLSession單例對象,創建一個downloadTask。- 注意此任務默認將文件下載到tmp文件夾,並且在下載結束後如果不處理會秒刪,一般的做法是把它移動到Document或者Caches中,當下載結束後會調用結構體,在結構體裏處理文件即可。
通過NSFileManager可以實現文件的複製、移動操作,回調的location是tmp中剛剛下載的文件的URL。
NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[NSURL URLWithString:@"http://127.0.0.1/lesson1/nav.dmg"] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { // 臨時下載到tmp,必須及時處理,否則會被系統秒刪。 // 應該將臨時文件移動到Caches文件夾 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 可以使用建議的文件名,與服務端一致 NSString *file = [path stringByAppendingPathComponent:response.suggestedFilename]; // 移動文件 NSFileManager *mgr = [NSFileManager defaultManager]; [mgr moveItemAtPath:location.path toPath:file error:nil]; }];
2.開啓任務
所有任務在創建時都是暫停的,應該手動啓動。[task resume];
大文件下載
大文件常常需要獲取進度,這就需要設置代理,而不是用block回調。
1.遵循代理方法,創建兩個成員,一個用於指向下載任務對象,另一個用於保存斷點數據。@interface ViewController () <NSURLSessionDownloadDelegate> @property (nonatomic, strong) NSURLSessionDownloadTask *task; @property (nonatomic, strong) NSData *resumeData; @end
2.獲取URLSession單例,創建下載任務,注意使用的方法與前面不同。
- 不要忘了保存task。
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[NSURL URLWithString:@"http://127.0.0.1/lesson1/nav.dmg"] ]; [task resume]; _task = task;
3.下載過程中會調用下面的代理方法,指示此次下載的字節數,一共下載的字節數與總字節數。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ NSLog(@"寫入量:%lld 下載進度:%f",bytesWritten,(double)totalBytesWritten/totalBytesExpectedToWrite); }
4.下載結束後回調用下面的代理方法,從中同樣要移動文件,只是如果要想拿到響應體response的suggestedFilename,需要通過downloadTask。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{ NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 可以使用建議的文件名,與服務端一致 NSString *file = [path stringByAppendingPathComponent:downloadTask.response.suggestedFilename]; // 移動文件 NSFileManager *mgr = [NSFileManager defaultManager]; [mgr moveItemAtPath:location.path toPath:file error:nil]; [self.btn setTitle:@"Start" forState:UIControlStateNormal]; }
5.如果要暫停下載,調用下面的方法,通過回調結構體拿到斷點數據,保存在我們之前創建的成員中以便恢復。
- 注意用weakSelf避免循環引用。
- 任務結束後就無效了,應該讓指針指向nil來釋放內存。
__weak typeof(self) weakSelf = self; [self.task cancelByProducingResumeData:^(NSData *resumeData) { // resumeData內部包含了下次繼續下載的開始位置 weakSelf.resumeData = resumeData; weakSelf.task = nil; }];
6.要恢復下載數據很容易,只需要通過斷點創建任務即可。
- 注意清空resumeData。
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; // 傳入上次暫停下載返回的數據 NSURLSessionDownloadTask *task = [session downloadTaskWithResumeData:self.resumeData]; [task resume]; _task = task; _resumeData = nil;
斷點續傳開始時會調用下面的代理方法說明文件信息。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{ }