1

connect というメソッドから URL のコンテンツを取得しようとしています。構成設定を読み取り、URL の取得を試みます。実行するには実行ループが必要なようです。私はそれが一度実行されるだけで完了すると思っていました。connect が呼び出されるたびに、この URL を 1 回取得する以外の理由で実行ループを実行する必要はないようです。これを行うより良い方法はありますか?

- (BOOL) connect 
{
    // read serverName and eventId from preferences
    NSMutableArray* preferences;
    preferences = [NSMutableDictionary dictionaryWithContentsOfFile:@"/tmp/wt.plist"];

    // if these values aren't nil or blank
    if ([preferences valueForKey:@"serverAddress"] && [preferences valueForKey:@"eventId"]) {

        [self setServerAddress:@"172.16.28.210"];
        [self setEventId:@"OT-3037009"];
    } else{
        // return some kind of error message
    }

    NSLog(@"VideoDataURL: %@", [self getVideoDataURL]);

    // grab the URL and query the server

    NSURL *myURL = [NSURL URLWithString:@"http://localhost"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:myURL
                                                           cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                                       timeoutInterval:2];

    __unused NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];

    [[NSRunLoop currentRunLoop] run];

    return TRUE;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    // This method is called when the server has determined that it
    // has enough information to create the NSURLResponse.

    // It can be called multiple times, for example in the case of a
    // redirect, so each time we reset the data.

    // receivedData is an instance variable declared elsewhere.
    [incomingData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    /* 
     * Called each time a chunk of data arrives
     */

    NSLog(@"received %lu bytes", [data length]);

    // Create a mutable data if it doesn't already exist
    if (!incomingData) {
        incomingData = [[NSMutableData alloc] init];
    }

    [incomingData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{
    /*
     * Called if the connection fails
     */

    NSLog(@"connection failed: %@", [error localizedDescription]);  
    incomingData = nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{
    /*
     * Called when the last chunk has been processed
     */

    NSLog(@"Got it all!");

    NSString *string = [[NSString alloc] initWithData:incomingData encoding: NSUTF8StringEncoding];

    incomingData = nil;

    NSLog(@"response is: %@", string);
}
4

3 に答える 3

10

メインスレッドから接続を開始している場合、はい、これは正しいです。実行ループについて考える必要がないように、GCD を使用してメイン スレッドで接続を作成および開始するだけです。

dispatch_async(dispatch_get_main_queue(), ^{
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
    [conn start];
});

どこからでも機能し、実行ループやスレッドを追跡する必要はありません。

于 2012-05-10T15:55:55.950 に答える
3

接続を生成しているワーカー スレッドの runLoop に、接続が完了するまで実行するように手動で指示するようにしてください。これを行わないと、Cocoa は自動的にスレッドをスリープ状態にするため、デリゲート メソッドが応答を受信しないように見えるのはなぜですか。

// The following is delcared within the scope of a NSThread, NSOperation, or GCD Block
//
// The NSURLConnection object and it's initialization/start methods
// |
// V
// Above the method call to the thread's runLoop.
//
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:<a time interval>];
// I use a minute, or 60.0, before I manually cancel the connection
// and send an error message back to the caller.

^接続を生成した後に呼び出す必要があるメソッドです。探している結果が得られるはずです。

非同期サーバー呼び出し/タスクを作成するときは、次の構造を念頭に置いてください。

スレッド

ランループ

仕事

各非同期タスクには、その存在期間中にイベントが継続的にポーリングされるように、独自の RunLoop が必要です。関連するタスクを実行するには、各 RunLoop がスレッドのスコープ内に存在する必要があります。

NSThread/NSRunLoop/NSURLConnection、Grand Central Dispatch、または NSOperation/NSOperationQueue を使用して、非同期ネットワーク タスクを手動で構築できます。操作/キューの方がオブジェクト指向であると感じ、ブロックベースのプログラミングはややこしいことがあるため、私はオペレーション/キューを好みます (これは、「dispatch_」呼び出しを使用した場合にリクエストを書き込む構造です)。結局のところ、プログラミングの好みに基づいてスレッドモデルを記述してください。どのアプローチでも同じ結果が得られます。

また、同期が必要なタスクの一部を実行している場合を除き、dispatch_sync を使用しないでください。そうしないと、UI がロックアップしてしまいます。アプリケーションの真の非同期モデルを作成するには、RunLoops の習得が必要です。

幸運を!

PS NSURLConnection は既に非同期で実行するように構築されていますが、真の非同期ネットワーク モデルを作成するには、アプリケーションがメイン スレッドとは別のスレッドで接続を生成する必要があります。

于 2013-08-13T14:49:16.800 に答える
0

同期リクエストに実行ループは必要ないと思います:

NSURLResponse* response = nil;
NSData* data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:nil];
于 2012-05-10T15:53:15.000 に答える