8

メインスレッドではなく別のスレッドからデリゲートメソッドを呼び出すように NSURLConnection を取得するにはどうすればよいですか。私は scheduleInRunLoop:forMode: をいじろうとしていますが、私が望むことをしていないようです。

大きなファイルをダウンロードする必要があり、メイン スレッドが頻繁に中断されるため、実行中の一部のレンダリングが不安定になり始めます。

NSURLRequest * request = [NSURLRequest requestWithURL:url];
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
NSRunLoop * loop = [NSRunLoop currentRunLoop];
NSLog(@"loop mode: %@",[loop currentMode]);
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];

私があまり見ないもう1つのことは「モード」です。文書化されているモードは2つしかないため、実際にテストすることはあまりありません。

何か案は?

ありがとう

4

4 に答える 4

6

いくつかのオプションがあります:

  1. デリゲート メソッドの実装では、dispatch_async.
  2. バックグラウンド スレッドで接続のスケジュールを開始します。

後者は次のように実行できます。

// all the setup comes here
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSRunLoop *loop = [NSRunLoop currentRunLoop];
    [connection scheduleInRunLoop:loop forMode:NSRunLoopCommonModes];
    [loop run]; // make sure that you have a running run-loop.
});

実行しているスレッドを保証したい場合は、呼び出しをdispatch_get_global_queue()適切に置き換えてください。

于 2011-12-26T15:34:01.827 に答える
2

別のスレッドでダウンロードを実行したい場合は、これらがあなたが探しているドロイドであると確信しています...

- (void) dispatchRequest{
    self->finished = NO;
    NSMutableURLRequest* request = //Formulate your request
    NSThread* download_thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadThreadLoop:) object:request];
    [download_thread start];
}
- (void) downloadThreadLoop:(NSMutableURLRequest*) request{

    NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

    while(!self->finished]){
        //This line below is the magic!
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    //...
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    //...
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    //...   
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    //...   
    self->finished = YES;
}
于 2012-06-25T16:17:47.303 に答える
0

本当に新しいスレッドでダウンロードを行う必要がある場合はdetachNewThreadSelector:toTarget:withObject:、 をセットアップ (および破棄) してから、のNSAutoreleasePoolような同期セレクターの 1 つを使用する方が簡単な場合があります。これは非同期を利用しません。NSDatadataWithContentsOfURL:NSURLConnectionDelegate

この呼び出しは同期的であるため、ファイルがダウンロードされるまで返されず、メイン スレッドがブロックされますが、新しいスレッドにいるため、返されません。これは通常、推奨されない動作であることに注意してください。最適化できるメイン スレッドで発生している他のコードはありますか?

于 2011-11-22T02:34:33.130 に答える
0

NSURLConnection は、すでにメイン スレッドから非同期的にダウンロードを行っています。あなたの質問が理解できたら、デリゲート メッセージをメイン スレッド以外のスレッドで送信したいですか? NSURLConnection の内部実装を変更できないため、これを行うことはできません。これをシミュレートするには、2 つの方法が考えられます。

  1. 自分自身をデリゲートとして割り当てるNSURLConnection(例: )のサブクラスを作成します。MyURLConnectionこれにより、意図的な保持サイクルが作成されることに注意してください。をサポートMyURLConnectionする新しい を定義する必要があります。これを と呼びましょう。独自のデリゲート メッセージを処理する場合は、好きなスレッドに転送またはディスパッチします。delegateNSURLConnectionDelegatefinalDelegateMyURLConnectionfinalDelegate

  2. オプション #1 に似ていますが、サブクラスはありません。メイン スレッドでデリゲート メソッドを処理し、NSURLConnection好きなスレッドに転送/ディスパッチします。

主な違いは、このように動作する再利用可能なサブクラスが必要か、それとも 1 回限りの実装かです。

編集:バックグラウンドでコードを実行する方法に関する提案を追加

バックグラウンドで応答を処理する場合は、オペレーションまたはグランド セントラル ディスパッチのいずれかを使用します。実行ループやスレッドの作成をいじる必要はありません。Apple のConcurrency Programming Guideを確認してください。

于 2011-11-22T04:09:15.050 に答える