Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Cocoa勉強会#62-新しい通信クラス群NSURLSessionを使ってみる

12,363 views

Published on

Cocoa勉強会#62
2013/10/19
新しい通信クラス群NSURLSessionを使ってみる
新居雅行

Published in: Technology
  • Follow the link, new dating source: ♥♥♥ http://bit.ly/39mQKz3 ♥♥♥
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Dating direct: ❶❶❶ http://bit.ly/39mQKz3 ❶❶❶
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Cocoa勉強会#62-新しい通信クラス群NSURLSessionを使ってみる

  1. 1. 新しい通信クラス群 NSURLSessionを使ってみる Cocoa Study #62 Oct 19, 2013 Masayuki Nii nii@msyk.net 13年10月18日金曜日 1
  2. 2. Agenda NSURLSessionのコンセプト NSURLConnectionとの違い Completion Handlerを使った通信 デリゲートを使った通信 13年10月18日金曜日 2
  3. 3. NSURLSessionのコンセプト と従来との違い 13年10月18日金曜日 3
  4. 4. iOS 7から搭載されたNSURLSession 対応するセッション(通信) • • • Default:NSURLConnectionに似た通信手法 Ephemeral:キャッシュなどに一切データを残さないの通信処理 Background:別プロセスでバックグランド処理 対応するタスク(作業) • • • Dataタスク:NSDataをアップロード、ダウンロード Downloadタスク:通信結果をファイルへバックグランドでダウン ロード Uploadタスク:ファイルからバックグランドでアップロード 基本的な使い方 • • • 13年10月18日金曜日 NSURLSessionConfigurationクラスのセッションの設定を用意 NSURLSessionクラスのインスタンスを生成 NSURLSessionTaskクラスを取得して通信 4
  5. 5. NSURLConnectionとの違い デリゲートは必須でなくなった • 簡単な処理はシンプルに記述できる バックグランド動作が可能になった • アプリケーションが終了しても通信を続ける セッションとタスクに分かれた • 証明書と認証の処理が別々のデリゲートで処理できるようになる NSDataだけでなく、ファイルやストリームも入出力と して指定できるようになった デリゲートが比較的整理された 13年10月18日金曜日 5
  6. 6. 通信部分の攻略法はどうなる? 新たに作る物で、NSURLConnectionを使う理由はない • ただし、iOS 7以降対応版である場合 従来のプログラムのNSURLConnectionはそのまま動く • だとしたら、無理にNSURLSessionにする必要もない We think... • • 13年10月18日金曜日 たぶん、2つのやり方が併用されるのは相当先まで続くだろう けど、サードパーティのライブラリが使われる比率は減る 6
  7. 7. Completion Handlerを使っ た通信 13年10月18日金曜日 7
  8. 8. NSURLSessionConfigurationクラス セッションのタイプに応じた以下のスタティクメソッド で生成 • • • + backgroundSessionConfiguration: + defaultSessionConfiguration + ephemeralSessionConfiguration 多数のプロパティがあり生成後に修正 • • • 13年10月18日金曜日 HTTPのヘッダ、携帯回線の可否、タイムアウト、クッキーの扱い TSL対応プロトコル、キャッシュや認証情報の保持 並列接続数、パイプライン、プロキシ 8
  9. 9. NSURLSessionクラス オブジェクトの生成 • • • + sessionWithConfiguration: + sessionWithConfiguration:delegate:delegateQueue: + sharedSession デリゲートとデリゲートキュー • • デリゲートはなくてもOKとなっている デリゲートキューにnilを指定するとシステムが与える NSURLSessionタスクの生成 • • • • • 13年10月18日金曜日 タスクのタイプに応じて多数のメソッドが定義されている 生成されるのは、NSURLSessionDataTask、 NSURLSessionDownloadTask、NSURLSessionUplodadTaskのいずれか NSURL、あるいはNSURLRequestを通信先で指定する Completion Handler(通信後に呼び出されるブロック)を使う場合には多 くのデリゲートは呼び出されない ハンドラ内は別スレッドで通信されるので、UIKitの処理に気をつける 9
  10. 10. デリゲートを指定しない通信 NSURL *currentURL = [NSURL URLWithString: @"http://msyk.net"]; NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration: config delegate: nil delegateQueue: nil]; NSURLSessionDataTask *task = [session dataTaskWithURL: currentURL completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error){ //通信後に呼び出されるブロック-Completion Handler //引数から通信結果が得られる。処理は別スレッド [session invalidateAndCancel]; }]; [task resume]; 13年10月18日金曜日 10
  11. 11. デリゲート無しの場合の注意 Completion Handlerは「別スレッド」で処理 • • なにもしなくても、コールバックは別スレッドになった delegateQueueはnilの場合「Serial Operation Queue」つまり、 mainQueueで得られるメインスレッド用のキューを使う [session invalidateAndCancel]が必要 • マニュアルには書いてある。ないとリークするそうです Completion Handlerを記述し、delegateもセットし て、デリゲートメソッドを実装したら… • 13年10月18日金曜日 デリゲートメソッドのほとんどは呼び出されない 11
  12. 12. NSURLSessionでタスクを返すメソッド Adding Data Tasks to a Session • • • • - dataTaskWithURL: dataTaskWithURL:completionHandler: dataTaskWithRequest: dataTaskWithRequest:completionHandler: Adding Download Tasks to a Session • • • • • • - downloadTaskWithURL: downloadTaskWithURL:completionHandler: downloadTaskWithRequest: downloadTaskWithRequest:completionHandler: downloadTaskWithResumeData: downloadTaskWithResumeData:completionHandler: Adding Upload Tasks to a Session • • • • • 13年10月18日金曜日 - uploadTaskWithRequest:fromData: uploadTaskWithRequest:fromData:completionHandler: uploadTaskWithRequest:fromFile: uploadTaskWithRequest:fromFile:completionHandler: uploadTaskWithStreamedRequest: 12
  13. 13. NSURLSessionの既定の動作 タスクにCompletion Handlerを実装した場合 • • • • 通常のHTTP通信は、リダイレクトを含めてそのまま可能 サーバ証明書が正しいHTTPS通信もそのまま可能 サーバ証明書が正しくない場合(おれおれ証明書)、通信はでき ず、-1202番のエラーを返す 認証が絡む場合デリゲートでの実装が一般的 デリゲートで実装する場合 • • 13年10月18日金曜日 通信中のプログレス表示などが可能になる デフォルトの動作をさせたい場合は対応するデリゲートメソッドは 実装しない 13
  14. 14. デリゲートを実装してみる 13年10月18日金曜日 14
  15. 15. デリゲートで記述可能なメソッド URLSessionDelegate(セッション) • • • - URLSession:didBecomeInvalidWithError: - URLSession:didReceiveChallenge:completionHandler: - URLSessionDidFinishEventsForBackgroundURLSession: URLSessionTaskDelegate(タスク一般) • • • • • - URLSession:task:didCompleteWithError: URLSession:task:didReceiveChallenge:completionHandler: URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend: URLSession:task:needNewBodyStream: URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler: URLSessionDataDelegate(データとアップロードタスク) • • • • - URLSession:dataTask:didReceiveResponse:completionHandler: URLSession:dataTask:didBecomeDownloadTask: URLSession:dataTask:didReceiveData: URLSession:dataTask:willCacheResponse:completionHandler: URLSessionDownloadDelegate(ダウンロードタスク) • - cancelByProducingResumeData: 返り値の指定 • 13年10月18日金曜日 completionHandler:の引数にあるブロックに引数を与えて呼び出す(returnじゃない!) 15
  16. 16. デリゲートを実装したときの一般的な通信処理 デリゲートの呼び出し結果 • • • • • urlString = http://msyk.dyndns.org/test.php -[Communication URLSession:dataTask:didReceiveResponse:completionHandle r:] -[Communication URLSession:dataTask:didReceiveData:] : -[Communication URLSession:task:didCompleteWithError:] We think... • 13年10月18日金曜日 以前と変わらず? 完了時の呼び出したエラーの有無で違っていな いで1つのメソッドになった! 16
  17. 17. 存在しないファイルにアクセスした場合 デリゲートの呼び出し結果 • • • • • • • urlString = http://msyk.dyndns.org/test1.php -[Communication URLSession:dataTask:didReceiveResponse:completionHandler:] HTTP Response Code = 404 -[Communication URLSession:dataTask:willCacheResponse:completionHandler:] -[Communication URLSession:dataTask:didReceiveData:] -[Communication URLSession:task:didCompleteWithError:] [error] (null) We think... • 13年10月18日金曜日 エラーは返さないので、レスポンスのステータスコードを見る必要が ある 17
  18. 18. 存在しないURLに接続しようとした デリゲートの呼び出し結果 • • • urlString = http://msyk1234.dyndns.org/ -[Communication URLSession:task:didCompleteWithError:] [error] Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo=0xdb4fe70 {NSErrorFailingURLStringKey=http:// msyk.netxxxxx, NSErrorFailingURLKey=http://msyk.netxxxxx, NSLocalizedDescription=A server with the specified hostname could not be found., NSUnderlyingError=0x8d59160 "A server with the specified hostname could not be found."} We think... • • 13年10月18日金曜日 完了のメソッドだけがデリゲートされる まあ、順当だろう 18
  19. 19. リダイレクト デリゲートの呼び出し結果 • • • • • • • urlString = http://msyk.dyndns.org/test.php -[Communication URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler :] -[Communication URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler :] -[Communication URLSession:dataTask:didReceiveResponse:completionHandler:] -[Communication URLSession:dataTask:didReceiveData:] : -[Communication URLSession:dataTask:willCacheResponse:completionHandler:] We think... • • 13年10月18日金曜日 単にリダイレクトをそのままリダイレクトするならデリゲートは不要 リダイレクトがあれば、willPerformHTTPRedirectionが呼び出される 19
  20. 20. HTTPSと認証 13年10月18日金曜日 20
  21. 21. 認証と証明書の対応 HTTPによるユーザ認証 • • タスク側で、デリゲートメソッドが呼び出される URLSession:task:didReceiveChallenge:completionHandler: 証明書の確認処理 • • セッション側で、デリゲートメソッドが呼び出される URLSession:didReceiveChallenge:completionHandler: 情報源 • • 13年10月18日金曜日 iOS Developer Libraryの「URL Loading System Programming Guide」にあるAuthentication Challenges and TLS Chain Validation に詳細が記載されているが、現時点ではNSURLConnectionのみの説明 このドキュメントに掲載されているサンプルプログラムを頼りにプログ ラムをする。このメソッドにユーザ名とパスワードを与えれば、確かに 認証は可能であるが… 21
  22. 22. Appleのドキュメントにある認証のためのコード -(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { if ([challenge previousFailureCount] == 0) { NSURLCredential *newCredential; newCredential = [NSURLCredential credentialWithUser:[self preferencesName] password:[self preferencesPassword] persistence:NSURLCredentialPersistenceNone]; [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge]; } else { [[challenge sender] cancelAuthenticationChallenge:challenge]; // inform the user that the user name and password // in the preferences are incorrect [self showPreferencesCredentialsAreIncorrectPanel:self]; } } 13年10月18日金曜日 22
  23. 23. HTTPの認証が必要なサイトへのアクセス 注意すべき点 • Completion Handlerだけの実装の場合、通信は成功するが、レスポンスコードが401 なので認証エラーと分かる 実際に認証がになったとき • ユーザ名とパスワードを含めたNSURLCredentialクラスのオブジェクトを返す デリゲートメソッドを実装した場合 • • • • • • • • • 13年10月18日金曜日 -[Communication URLSession:task:didReceiveChallenge:completionHandler:] [authMethod]NSURLAuthenticationMethodDefault -[Communication URLSession:dataTask:didReceiveResponse:completionHandler:] HTTP Response Code = 200 -[Communication URLSession:dataTask:didReceiveData:] : -[Communication URLSession:dataTask:willCacheResponse:completionHandler:] -[Communication URLSession:task:didCompleteWithError:] [error] (null) 23
  24. 24. 認証に対応するデリゲートメソッドの例 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { NSString *authMethod = challenge.protectionSpace.authenticationMethod; if ( [authMethod isEqualToString: NSURLAuthenticationMethodDefault] ) { NSURLCredential *credential = [NSURLCredential credentialWithUser: self.username password: self.password persistence: NSURLCredentialPersistenceNone]; completionHandler(NSURLSessionAuthChallengeUseCredential, credential); } else { completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); } } 13年10月18日金曜日 24
  25. 25. HTTPSによる通信と証明書 注意すべき点 • • Completion Handlerを使用する場合、何もしなくてもOK NSURLConnectionでは動作が大きく異なるので注意が必要 デリゲートの呼び出し結果 • • • • • urlString = https://msyk.net/ -[Communication URLSession:dataTask:didReceiveResponse:completionHandler:] -[Communication URLSession:dataTask:didReceiveData:] -[Communication URLSession:task:didCompleteWithError:] [error] (null) おれおれ証明書でも許可する場合 • • 13年10月18日金曜日 デリゲートメソッドを実装して、判定して必要な結果を返す 正しい証明書の場合でも、適切な結果を返す必要がある 25
  26. 26. 証明書に対応するデリゲートメソッドの例 Security.frameworkの追加が必要 - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { NSString *authMethod = challenge.protectionSpace.authenticationMethod; if ( [authMethod isEqualToString: NSURLAuthenticationMethodServerTrust] ) { SecTrustRef secTrustRef = challenge.protectionSpace.serverTrust; if (secTrustRef != NULL) { SecTrustResultType result; OSErr er = SecTrustEvaluate( secTrustRef, &result ); if ( er != noErr) { completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil); } // nilを返した場合には通信は許可されない if ( result == kSecTrustResultRecoverableTrustFailure ) { NSLog( @"---SecTrustResultRecoverableTrustFailure" ); //信頼できない証明書の場合の対処をここに記述。拒否ならreturn } } NSURLCredential *credential = [NSURLCredential credentialForTrust: secTrustRef]; completionHandler(NSURLSessionAuthChallengeUseCredential, credential); // NSURLCredentialクラスのオブジェクトを返せば許可したことになる } } 13年10月18日金曜日 26
  27. 27. まとめ NSURLSessionは待ち望まれていた通信処理の大改良 デリゲート無しでの処理で概ね通信は可能 バックグランド処理やファイル直接処理は期待大 13年10月18日金曜日 27

×