2011-09-14 8 views
29

NSDataには常に+dataWithContentsOfURL:options:error:という非常に便利なメソッドがありました。便利ですが、現在のスレッドの実行もブロックされます。つまり、基本的にはプロダクションコードでは役に立ちませんでした(無視するNSOperation)。私はこの方法をあまり使用しなかったので、それが存在することを完全に忘れてしまった。最近まで。NSURLConnectionとNSData + GCDの比較

NSURLConnectionDelegateさまざまな方法を扱うダウンロードクラスを作成し、徐々にデータを構築し、エラーを処理しますできるだけ多くの要求に対して再利用できるほど十分です。

私の典型的なダウンローダクラスは、100行の球場のどこかで動作しているとします。これは、非同期的に行うための行で、NSDataは1行に同期して実行できます。より複雑になると、そのダウンローダクラスは、完了とエラーをその所有者に伝えるために独自のデリゲートプロトコルを必要とし、所有者は何らかの形でそのプロトコルを実装する必要があります。今

、グランドセントラル派遣を入力し、私は限り素晴らしくシンプルな何かを行うことができます:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { 

    NSData* data = [NSData dataWithContentsOfURL:someURL]; 
    // Process data, also async... 

    dispatch_async(dispatch_get_main_queue(), ^(void) { 
     // Back to the main thread for UI updates, etc. 
    }); 
}); 

そして私は右にライン、私が欲しいのどこにその吸盤を投げることができます。ダウンロードクラスを必要とせず、接続の代理メソッドを処理する必要もありません。わずか数行で簡単な非同期データです。このアプローチと私のGCD前アプローチとの間の格差は、あまりにも真のアラームであることをトリガするのに十分な大きさです。

NSURLConnectionの代わりにNSData + GCDを単純なデータダウンロードタスクに使用する場合の注意点がありますか(ダウンロードの進捗状況は気にしないと仮定します)?

+2

私はあなたの進行状況の表示、キャンセル、および認証に同意します。 – Daniel

答えて

22

あなたはここで多くの機能を失っている:

  • は、ダウンロードの進行を追跡することはできません
  • ダウンロードをキャンセルすることはできません
  • 可能認証プロセスに
  • を管理することはできませんあなたあなたはしばしば実際の状況であなたのネットワークを失うので、は本当に重要なですが、特にiPhoneのようなモバイル開発ではエラーを簡単に処理できません。そのようなネットワークエラーを追跡することは非常に重要ですiOS向けに開発する場合)

と思われます。


正しいアプローチは、ダウンロードを管理するクラスを作成することです。

シンプルで、私はブロックで使いやすいようにAPIを作っ例えば自分のOHURLLoaderクラスを参照してください。

NSURL* url = ... 
NSURLRequest* req = [NSURLRequest requestWithURL:url]; 

OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req]; 
[loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) { 
    NSLog(@"Download of %@ done (statusCode:%d)",url,httpStatusCode); 
    if (httpStatusCode == 200) { 
     NSLog(%@"Received string: %@", loader.receivedString); // receivedString is a commodity getter that interpret receivedData using the TextEncoding specified in the HTTP response 
    } else { 
     NSLog(@"HTTP Status code: %d",httpStatusCode); // Log unexpected status code 
    } 
} errorHandler:^(NSError *error) { 
    NSLog(@"Error while downloading %@: %@",url,error); 
}]; 

は、詳細はgithubの上README fileとサンプルプロジェクトを参照してください。

この方法:あなたはまだNSURLConnection(とが提供する非同期メソッドに依存している

  • as the Apple's documentation says about Concurrency Programming APIはすでに、非同期タスクを作る代わりに、可能な場合は、別のスレッドテクノロジに依存するのでそれを使用するために存在している場合)
  • NSURLConnection(エラーハンドリングなど)の利点を維持する
  • しかし、デリゲートメソッドを使用する場合よりもコードを読みやすくするブロック構文の利点もあります。
+0

すべての良い点。一方、エラー処理、私はエラーを介して可能性が期待されていた:メソッドへの引数。そうでない場合、それは確かに大きな欠点になるでしょう。 –

+0

'dataWithContentsOfURL:options:error:'を使うとエラー処理ができますが、あなたの質問と同じように 'dataWithContentsOfURL:'を使うのではないでしょう。しかしさらに、ネットワークエラー、HTTPエラー、ヘッダーへのアクセスなどはありません。 – AliSoftware

+0

+1素晴らしい答え。あなたのOHURLLoaderを愛し、それは本当に大事なものでした! – Groot

12

WWDC 2010 Session Videos

  • WWDC 2010のセッション207 - iPhone OSのネットワークのアプリ、パート1
  • WWDC 2010のセッション208 - iPhone OSのネットワークのアプリ、パート2

講師は言った

"Threads Are Evil™".

ネットワークプログラミングでは、RunLoopで非同期APIを使用することを強く推奨します。

NSData + GCDを次のように使用すると、接続ごとに1つのスレッドが使用されるためです。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { 
    NSData* data = [NSData dataWithContentsOfURL:someURL]; 

多くの接続と多くのスレッドを使用する可能性があります。 GCDを使うのは簡単すぎる:-) 次に、多くのスレッドは、そのスタックに膨大な量のメモリを食いつぶします。 したがって、AliSoftwareによれば、非同期APIを使用する方がよいでしょう。

2

OS X v10.9およびiOS 7では、好ましい方法はNSURLSessionです。それはあなたに良い、ブロックベースのインターフェイスとキャンセル、一時停止、バックグラウンドダウンロードなどの機能を提供します。

関連する問題