iOS NSURLSessionネットワークリクエスト-ファイルダウンロード-アップロード-バックグラウンドダウンロードを実現


*セッションNSURLSession
NSURLConnectionは、cookies、認証情報などの共通リソースをグローバル状態で管理していますが、2つの接続で異なるリソース構成が必要な場合は解決できません.この問題はNSURLSessionで解決できます.NSURLSessionは同時に複数の接続に対応しています.セッションはファクトリメソッドで作成され、同じセッションで同じ状態情報が使用されます.NSURLSessionサポートプロセスの3つのセッション:1.defaultSessionConfiguration:データをキャッシュするためのハードディスク(HDD)用のプロセス内セッション(デフォルトセッション)    2. ephemeralSessionConfiguration:一時的なプロセス内のセッション(メモリ)で、クッキーはキャッシュされず、ローカルに格納され、メモリにのみ格納され、アプリケーションが終了するとデータも消える.backgroundSessionConfiguration:デフォルトのセッションよりも、バックグラウンドで県城を開いてネットワークデータ処理を行うバックグラウンドセッション
正確な制御タスクのキャンセル、保留、リカバリ
1.要求データ
#pragma mark ---      request --- session ---- sessionDataTask

- (void)loadData
{
    // 1.   url
    NSString *urlString = [NSString stringWithFormat:@"url"];
    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *url = [NSURL URLWithString:urlString];
    // 2.     
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 3.      (       ,     )
    
    NSURLSession *session = [NSURLSession sharedSession];
    
    //       
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if (!error) {
            NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"%@", dataStr);
        } else {
            NSLog(@"error is %@", error.localizedDescription);
        }
        
    }];
    
    //     ,     
    [dataTask resume];
}

2.ファイルアップロード
#pragma mark -----     
- (void)upDataFile
{
    /**
     *                 Content-Type  ,     URL  , 
     
     application/x-www-form-urlencoded:   ,            url  ,       ,              。
     multipart/form-data:       ,       ,       ,        (           ) 。
     text/plain:        ,       ,           “+”,          。
     application/json:json    ,         。
     text/xml:xml    ,        。
     
     multipart/form-data       ,
     */
    // 1.   URL
    NSString *urlStr = @"url";
    urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *url = [NSURL URLWithString:urlStr];
    // 2.     
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    //       POST
    request.HTTPMethod = @"POST";
    
    // 3.        
    NSString *path = [[NSBundle mainBundle] pathForResource:@"123" ofType:@"123"];
    NSData *data = [NSData dataWithContentsOfFile:path];
    
    //   request body
    request.HTTPBody = data;
    
    //      Content-Length
    [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)data.length] forHTTPHeaderField:@"Content-Length"];
    //      Content-Type
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",@"Xia"] forHTTPHeaderField:@"Content-Type"];
    
    // 4.     
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error) {
            //     
        }else {
            //     ,   error  
            NSLog(@"error --- %@", error.localizedDescription);
        }
    }];
    //          
    [uploadTask resume];
    
}

3.ファイルのダウンロード
#pragma mark ---     
/**
 *    NSURLSessionDownloadTask         :
                       ,                    
 */
- (void)downLoadFile
{
    // 1.   url
    NSString *urlStr =[NSString stringWithFormat:@"%@", @"url"];
    urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *Url = [NSURL URLWithString:urlStr];
    
    //     
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:Url];
    
    //     
    NSURLSession *session = [NSURLSession sharedSession];
    
    NSURLSessionDownloadTask *downLoadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error) {
            //     
            //    location           ,               
            NSError *saveError;
            //            
            NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
            NSString *savePath = [cachePath stringByAppendingPathComponent:@"fileName"];
            NSURL *saveURL = [NSURL fileURLWithPath:savePath];
            
            //      cache   
            [[NSFileManager defaultManager] copyItemAtURL:location toURL:saveURL error:&saveError];
            if (!saveError) {
                NSLog(@"    ");
            } else {
                NSLog(@"error is %@", saveError.localizedDescription);
            }
        } else {
            NSLog(@"error is : %@", error.localizedDescription);
        }
    }];
    //     ,     
    [downLoadTask resume];
    
}

4.ファイルのダウンロードのキャンセル、保留、ダウンロードの継続
#pragma mark --     
-(void)cancleDownLoad
{
    [_downloadTask cancel];
}
#pragma mark ---     
- (void)suspendDownload
{
    [_downloadTask suspend];
}
#pragma mark ----       
- (void)resumeDownLoad
{
    [_downloadTask resume];
    

}

5.NSURLSessionのエージェントメソッド
#pragma mark ---- downLoadTask     
//            ,       
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    //       
    
}

//     
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    NSError *error;
    NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *savePath = [cachePath stringByAppendingPathComponent:@"savename"];
    
    NSURL *saveUrl = [NSURL fileURLWithPath:savePath];
    //            
    [[NSFileManager defaultManager] copyItemAtURL:location toURL:saveUrl error:&error];
    if (error) {
        NSLog(@"Error is %@", error.localizedDescription);
    }
}

//                    [_downLoadTask resume]
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
    
    
}


#pragma mark ---     ,         
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    
}
#pragma mark --- session              (          UI)
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
    AppDelegate *appdelgate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    
    if (appdelgate.backgroundSessionCompletionHandler) {
        void (^completionHandle)() = appdelgate.backgroundSessionCompletionHandler;
        appdelgate.backgroundSessionCompletionHandler = nil;
        completionHandle();
    }
}

6.バックグラウンドダウンロード
NSURLSessionサポートプログラムのバックグラウンドダウンロードとアップロード、アップル公式はそれをプロセス以外のアップロードとダウンロードと呼び、これらのタスクはアプリケーション自体ではなくバックグラウンドデーモンスレッドに任せて完了します.タイムリーなファイルはダウンロードとアップロード中にクラッシュしても実行を続けることができます(ユーザーが強制的にプログラムを閉じるとNSURLSessionは接続を切断します)**ユーザー体験を高めるために、ダウンロード中に進捗バーが更新され続け、プログラムがバックグラウンドに入った後、実際にiOSシステムにタスクを渡してスケジュールされていますが、具体的にはいつダウンロードが完了するか分かりません.ダウンロードが完了した場合、ファイルのダウンロードの進捗状況は100の場所にあるはずです.プログラムはバックグラウンドでプログラムUIを更新できないため、アプリケーションエージェント(AppDelegate)メソッドでUI更新を行います.
NSURLSessionがバックグラウンドでいくつかのタスクを開くと、他のいくつかのタスクが完了するとアプリケーションが呼び出されます.
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier 
completionHandler:(void(^))completionHandlerエージェントメソッド
このメソッドには、アプリケーションですべての処理が完了したことを示すcompetionHandlerが含まれます.通常、このオブジェクトは保存されます.
最後のタスクが完了するまで、セッションID(sessionConfigで設定されている)によって適切なセッションが見つかり、NSURLSessionの
-(void)R u r s e s t i n D i d F i n i s h E v e n t s ForBackgroundURLSession:(NSURLSession*)セッションエージェントメソッドです.このメソッドでは通常
UIの更新を行い、completionHandlerを呼び出してシステムがすべての操作を完了したことを通知します.
#pragma mark ---     
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
    self.backgroundSessionCompletionHandler = completionHandler;
}

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
    AppDelegate *appdelgate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    
    if (appdelgate.backgroundSessionCompletionHandler) {
        void (^completionHandle)() = appdelgate.backgroundSessionCompletionHandler;
        appdelgate.backgroundSessionCompletionHandler = nil;
        completionHandle();
    }
}