0

ビューを切り替えるために UITabBarController を利用するアプリを書いています。1 つのタブは、UITableView に入力する前に、JSON データを収集して処理するための Web 要求を行います。このデータをバックグラウンドで読み込もうとしているので、ユーザーがタブを押してもテーブルの表示に遅延はありません。ActivityIndi​​cator が表示され、テーブルにデータがロードされます。

各リクエストが行われ、処理され、結果が NSMutableArray に配置されます。これは並べ替えられ、UITableView に追加されます。

dispatch_sync を使用すると、データが読み込まれ、配列が作成されて正常に表示されますが、ビューの UI の読み込みがブロックされます。何らかの理由でこのクエリをバックグラウンド キューに取得していないため、考えています。dispatch_async を使用すると、メイン スレッドで NSMutableArray にアクセスしようとすると例外が発生します。

したがって、私の質問は、ユーザーがこの TableView を含むタブに切り替え、データの読み込みと処理中に (バックグラウンドで) ActivityIndi​​cator を提示し、完了すると UITableView が処理された状態で読み込まれるようにするための適切なパターンは何ですか?データ。

UITableViewController からの関連コード:

#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

- (void)viewDidLoad
{
    [super viewDidLoad];

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    currentLat = appDelegate.currentLatitude;
    currentLong = appDelegate.currentLongitude;

    finalDistanceArray = [[NSMutableArray alloc] init];

    [self compareLocationMMC];
    [self compareLocationLVMC];
    [self compareLocationSBCH];
    [self compareLocationGVCH];
    [self compareLocationSYVCH];

    NSSortDescriptor *lowestToHighest = [NSSortDescriptor sortDescriptorWithKey:@"distance" ascending:YES];

    [hospitalList sortUsingDescriptors:[NSArray arrayWithObject:lowestToHighest]];  

}

- (void)compareLocationMMC {


NSString * searchURL = [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=true", currentLat.floatValue, currentLong.floatValue, MMC_LAT, MMC_LON];
NSURL * myURL = [NSURL URLWithString:searchURL];

dispatch_sync(kBgQueue, ^{
    NSData* data = [NSData dataWithContentsOfURL: 
                    myURL];
     [self performSelectorOnMainThread:@selector(fetchedData:) 
                          withObject:data waitUntilDone:YES];
});


}
//The compareLocationXXX method is repeated 4 more times with different search strings

- (void)fetchedData:(NSData *)responseData {

//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization 
                      JSONObjectWithData:responseData 

                      options:kNilOptions 
                      error:&error];

NSArray* stationDistance = [json objectForKey:@"routes"]; 

NSDictionary* legs = [stationDistance objectAtIndex:0];

NSArray* legsBetween = [legs objectForKey:@"legs"];

NSDictionary* distanceBetween = [legsBetween objectAtIndex:0];

finalDistance = [distanceBetween valueForKeyPath:@"distance.text"];

[finalDistanceArray addObject:finalDistance];

}
4

1 に答える 1

0

Dispatch_sync()ブロックをエンキューするために実行を停止するため、実際には呼び出し元のスレッドをブロックします。Dispatch_async呼び出し元の関数を再開できるため、はるかに優れた選択です。メインスレッドで完了コードを実行できるように、1 つの呼び出しを別の呼び出し内にラップできます。これにより、コードの実行が非常に読みやすくなります。

// Turn on status bar spinner, for example
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    // Do background stuff here
        ....
    NSData* data = [NSData dataWithContentsOfURL:myURL];
    // used parsed data to populate data structure of some type
        ....
    dispatch_async(dispatch_get_main_queue(), ^{
        // Use background stuff here
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    });
});

のようなコールバック ベースの APINSURLConnectionは、ネットワークの読み込みにはおそらく最適ですが、これはかなりうまく機能します。特に小さなリクエストの場合。

于 2012-02-14T02:48:56.407 に答える