web-dev-qa-db-ja.com

GCDと非同期NSURLConnection

NSURLConnection(標準の非同期接続)を作成すると、同じスレッドでコールバックすることを知っています。現在、これは私のメインスレッドにあります。 (うまくいきます)。

しかし、私は今、他の何かに同じコードを使用しているので、UIをきびきびと保つ必要があります。

私が行った場合

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    /* and inside here, at some NSURLConnection is created */


});

.. NSURLConnectionが作成されたが、URL接続が戻る前にスレッドが消える可能性はありますか?

私はGCDに不慣れです。 URL接続が戻るまでスレッドを存続させるにはどうすればよいですか、またはこれを行うためのより良い方法はありますか?

24
bandejapaisa

したがって、実際の問題は、ブロックが実行されているスレッドの存続期間ではなく、この特定のスレッドで、接続から返されるイベントを受信するように実行ループが構成および実行されないという事実です。

では、これをどのように解決しますか?考えるべきさまざまなオプションがあります。私はいくつかリストすることができます、そして他の人がもっとリストするだろうと確信しています。

1-ここでは同期接続を使用できます。欠点の1つは、認証、リダイレクト、キャッシュなどのコールバックを取得できないことです(同期接続の通常の欠点はすべて)。さらに、各接続はもちろん一定期間スレッドをブロックするため、これらの多くは、一度にいくつかのスレッドをブロックする可能性があり、コストがかかります。

2-接続が単純で、iOS5を使用している場合は、次の方法を使用できます。

_+ (void)sendAsynchronousRequest:(NSURLRequest *)request
                          queue:(NSOperationQueue*) queue
              completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))
_

これにより、非同期接続が開始され、完了ハンドラー(成功または失敗)を指定できるようになりますおよびそのブロックをスケジュールするNSOperationQueue。

繰り返しになりますが、認証やキャッシュなどに必要なコールバックを取得できないという欠点があります。ただし、少なくとも、実行中の接続によってブロックされたスレッドがぶら下がっていません。

-iOS5のもう1つのオプションは、キューを設定することですすべてのデリゲートコールバックに対して

- (void)setDelegateQueue:(NSOperationQueue*) queue NS_AVAILABLE(10_7, 5_0);

これを使用すると、すべてのデリゲートメソッドは、指定したNSOperationQueueのコンテキストで実行されます。したがって、これはオプション#2に似ています。認証、リダイレクトなどを処理するために、すべてのデリゲートメソッドを取得することを期待してください。

4-これらの接続を管理するために特別に制御する独自のスレッドを設定できます。そして、そのスレッドを設定する際に、runloopを適切に構成します。これはiOS4と5で正常に機能し、処理したいすべてのデリゲートコールバックを明らかに提供します

5-非同期接続処理のどの部分が本当に UIに干渉しているのかを考えるかもしれません。通常、接続を開始したり、デリゲートコールバックを受信したりすることは、それほど費用がかかりません。高価な(または不確定な)コストは、多くの場合、最後に収集するデータの処理にかかります。ここで質問するのは、非同期接続を開始するためだけにキューのブロックをスケジュールすることで本当に時間を節約しているのでしょうか。非同期接続はすぐにオフになり、とにかく別のスレッドで処理を実行します。

したがって、メインスレッドから接続を開始し、メインスレッドですべてのデリゲートコールバックを受信して​​から、それらのデリゲートメソッドの実装で他のキューまたはスレッドで実行する必要のある高価な作業をすべて実行します。

だからこのようなもの:

_- (void)connectionDidFinishLoading:(NSURLConnection *)connection {      
        // go ahead and receive this message on the main thread
        // but then turn around and fire off a block to do the real expensive work

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

         // Parse the data we've been collecting

        });

    }
_

繰り返しますが、これは包括的ではありません。ここでの特定のニーズに応じて、これを処理する方法はたくさんあります。しかし、私はこれらの考えが役立つことを願っています。

37
Firoze Lafeer

スレッドが消えた理由への答えと同じように(そして将来の参照のために)、NSURLConnectionにはrunloopが必要です。追加した場合

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];

接続が正しく実行され、接続が完了するまでスレッドが消えないことがわかります。

9
Tony Million

まず、ブロックとその中で使用するすべての変数がGCDにコピーされるため、コードはスレッドではなくグローバルキューで実行されます。

データをメインスレッドに戻したい場合は、データがフェッチされた後に非同期呼び出しをネストできます。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"www.stackoverflow.com"]];
    NSURLResponse *response;
    NSError *error;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    if (error) {
        // handle error
        return;
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        // do something with the data
    });
});

しかし、NSURLConnectionに組み込まれている非同期サポートを使用してみませんか? NSOperationQueueが必要ですが、ネットワークフェッチを大量に実行している場合は、とにかくそれが方法です。

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"www.stackoverflow.com"]];
[NSURLConnection sendAsynchronousRequest:request
                                   queue:self.queue // created at class init
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
                           // do something with data or handle error
                       }];

個人的には、AFNetworkingやASIHTTPRequestなどのライブラリを使用して、ネットワーキングをさらに簡単にします。どちらもブロックをサポートします(前者は、GCDを利用し、もう少し最新です)。

3
rich.e
dispatch_queue_t queue = dispatch_get_global_queue(  DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
        [btnCreateSmartList setEnabled:NO];
        [dbSingleton() createEditableCopyOfDatabaseIfNeeded];
        [dbSingleton() insert_SMART_PlaceList:txtListName.text :0:txtTravelType.text:          [strgDuration intValue]:strgTemprature:Strgender:bimgdt];
        [self Save_items];
//*********navigate new
            dispatch_async(dispatch_get_main_queue(), ^{
                [activityIndicator stopAnimating];
                [self performSelector:@selector(gonext_screen) withObject:nil afterDelay:0.0];
            });
        });
0
mahendra