1

こんにちは。私はバックエンドRailsサーバーに対して多くのhttpクエリを使用するiOSプログラムを作成しているため、以下のようなコードが大量にあります。この場合、UITableView:を更新しています。

//making requests before this...
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse* response, NSData* data, NSError* error)
{
    NSLog(@"Request sent!");

    NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
    NSLog(@"Response code: %d", [httpResponse statusCode]);
    if ([data length] > 0 && error == nil){
        NSLog(@"%lu bytes of data was returned.", (unsigned long)[data length]); }
    else if ([data length] == 0 &&
             error == nil){
        NSLog(@"No data was returned.");
    }
    else if (error != nil){
        NSLog(@"Error happened = %@", error); }

    id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
    if (jsonObject != nil && error == nil){
        NSLog(@"Successfully deserialized...");
        if ([jsonObject isKindOfClass:[NSDictionary class]]){
            NSDictionary *deserializedDictionary = (NSDictionary *)jsonObject;
            NSLog(@"Dersialized JSON Dictionary = %@", deserializedDictionary);
            [listOfItems addObject:deserializedDictionary];
        }
        else if ([jsonObject isKindOfClass:[NSArray class]]){
            NSArray *deserializedArray = (NSArray *)jsonObject; 
            NSLog(@"Dersialized JSON Array = %@", deserializedArray);
            [listOfItems addObjectsFromArray:deserializedArray];
        }
        else {
            /* Some other object was returned. We don't know how to deal
             with this situation as the deserializer only returns dictionaries
             or arrays */ }
    }
    else if (error != nil){
        NSLog(@"An error happened while deserializing the JSON data., Domain: %@, Code: %d", [error domain], [error code]); 
    }
    [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
}];
//the place where never runs
NSLog(@"End of function.");

問題は次のとおりです。通常、最後の行はコードブロックの前に実行されます。ブロック後のコードが実際にブロックの後に実行されるようにするにはどうすればよいですか?

ブロックが他のスレッドを使用していることを認識しています。そのため、。performSelectorOnMainThreadの直接呼び出しの代わりに関数を使用しています[self.tableView reloadData]。しかし、後で何か他のことをしたい場合、どうすればよいですか?

また、誰かがこれを行うためのいくつかのより良い方法を示すことができますか?私はバックエンドに大規模な呼び出しを行うための最良の方法を見つけようとしています。非同期リクエストを作成する方法はいくつかあります。たとえば、このブロック方法や、デリゲートクラスを呼び出す昔ながらの方法があります。コードのリファクタリングの進行中に、独自のデリゲートクラスを作成し、他のクラスにそれを呼び出させようとしましたが、特に複数の関数を使用するクラスの場合、接続のデータが返されるコールバック関数の正しい動作を特定することは困難です。さまざまなリクエストを呼び出します。そして、私は同期呼び出しを使いたくありません。

ご回答ありがとうございます。また、コードのバグを指摘することも歓迎します。

4

1 に答える 1

2

ディスパッチグループを使用できます

サンプルコード:

- (void)doSomethingAndWait {
// synchronous method
// called in main thread is not good idea.
NSAssert(! [NSThread isMainThread], @"this method can't run in main thread.");

dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);

//making requests before this...
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse* response, NSData* data, NSError* error)
{
    // your work here.


    dispatch_group_leave(group);
}];

// wait for block finished
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);

//will call until block is finished.
NSLog(@"End of function.");
}

そして、そのメソッドを呼び出すには、メインスレッドで呼び出さないようにする必要があります。

あなたはそれをこのように呼ぶべきです

dispatch_queue_t queue = dispatch_queue_create("com.COMPANYNAME.APPNAME.TASKNAME", NULL);
    dispatch_async(queue, ^{
        [self doSomethingAndWait];
    });
于 2012-07-21T10:26:17.430 に答える