9

私のアプリには、UITableViewController があります。

その tableView は 3 つのセクションに分かれています。

これらの各セクションのデータをサーバーからダウンロードします。これを行うには、3 つの関数 (たとえば、f1 f2 と f3) があります。それぞれが、テーブルのデータ ソースとして使用される対応する NSArray を更新します。

今私が望むのは、この関数を使用してデータをリロードし、この 3 つの関数が完了したら tableView を更新することですが、ユーザーを邪魔することはありません。

私は非同期リクエスト、ブロック、スレッドなどに慣れていないので、ヒントを探しています。

実際、ここに私がしていることがあります:

-(void)viewDidLoad
{
    //some settings

    [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:@selector(reloadDatas) userInfo:nil repeats:YES];

    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        [self reloadDatas];
    });
}

-(void)reloadDatas
{
    dispatch_queue_t concurrentQueue = dispatch_get_main_queue();
    dispatch_async(concurrentQueue, ^{
        [self f1];
        [self f2];
        [self f3];
        [myDisplayedTable reloadData];
    });
}

-(void)f1
{
    //load datas with a url request and update array1
}
-(void)f2
{
    //load datas with a url request and update array2
}
-(void)f3
{
    //load datas with a url request and update array3
}

しかし、ここでは、私の tableView は更新されるまで「凍結」されています。

f1 f2 と f3 の実行順序は気にしませんが、tableView を更新する前に、この 3 つの関数が完了するまで待つ必要があります。

ご協力いただきありがとうございます。

編集

ご回答ありがとうございます。

実用的なソリューションは次のとおりです。

mros が提案するように、viewDidLoad からディスパッチ キューを削除し、reloadDatas に置き換えます。

dispatch_queue_t concurrentQueue = dispatch_get_main_queue();

dispatch_queue_t mainThreadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

最後に、メインスレッドでテーブルをリロードします

dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });
4

4 に答える 4

5

したがって、「バックグラウンド スレッド」は実際にはメイン スレッドです。実際に別のスレッドを取得するには、dispatch_get_global_queue を使用して優先順位を指定する必要があります。また、ビュー コントローラのライフサイクル メソッドはすべてメイン スレッドで呼び出されるため、viewDidLoad のディスパッチ async は役に立ちません。f1、f2、および f3 メソッドで次のようにすることをお勧めします。

非同期 URL リクエストを起動することから始め、完了ブロックで arrayX を更新し、テーブルビューの特定のセクションをリロードします。このようにして、3 つの要求すべてを同時に発生させることができ、テーブルはそれぞれが終了したときに必要なデータを更新するだけです。または、一度だけリロードしたい場合は、concurrentQueue 変数をバックグラウンド スレッドに置き換えて[tableView reloadData]から、メイン スレッドで実行します。

于 2013-06-27T16:37:43.267 に答える
3

以前の答えは絶対に正しいです。ただし、 reloadDatas と viewDidLoad の実装には少し問題があります。

明確にするために:

時間のかかるデータの読み込みをバックグラウンド スレッドで完了し、メイン スレッドでデータの準備ができたら UI/セルを更新します。

そのようです:

  -(void)viewDidLoad
    {
       dispatch_queue_t concurrentQueue = dispatch_queue_create("com.my.backgroundQueue", NULL);
        dispatch_async(concurrentQueue, ^{
            [self reloadDatas];
        });
    }

-(void)reloadDatas
{
    // Expensive operations i.e pull data from server and add it to NSArray or NSDictionary
      [self f1];
      [self f2];
      [self f3];

    // Operation done - now let's update our table cells on the main thread  

    dispatch_queue_t mainThreadQueue = dispatch_get_main_queue();
    dispatch_async(mainThreadQueue, ^{

        [myDisplayedTable reloadData]; // Update table UI
    });
}
于 2013-06-27T20:53:01.710 に答える
2

もう1つ。サーバーからデータを取得して表のセルを更新することは、非常に一般的です。ここではキューやタイマーは必要ありません。ここに別の構造があります。

サーバーから mp3 をプルしているとします。モデル クラスは次のとおりです。Music.h/m モデル マネージャは次のとおりです。MusicManager.h/m (シングルトン) - 音楽オブジェクトの配列が含まれます。シングルトンは基本的にデータソースです。そして最後にあなたの UItableViewController : MusicTableVC.h/m

MusicManager.h/m :サーバーからプルした Music.h オブジェクトをロードする NSMutableArray がありますTableViewController を待たずに、アプリが読み込まれるとすぐにそれを行うことができます。

MusicManager 内には、mutableArray に項目を追加または削除し、カウントともちろんネットワーク メソッドを提供するヘルパー メソッドがいくつかあります。

最後に : ネットワーク コードに通知を投稿します。UITableViewController は、その通知をリッスン/監視し、それに応じて「リロード」する必要があります。

 [[NSNotificationCenter defaultCenter] postNotificationName:@"NewMusicAdded" object:nil];

サーバーからデータをクエリし、データを Music オブジェクトに解析して NSMutable 配列に追加し、通知を投稿してテーブル自体を更新させます。

かなりスタンダードなレシピ。

于 2013-06-28T20:41:51.617 に答える
2

reloadDatasメソッドでは、次の行を変更する必要があります。

dispatch_queue_t concurrentQueue = dispatch_get_main_queue();

に:

dispatch_queue_t concurrentQueue = dispatch_queue_create("some queue", NULL);

ただし、 を呼び出すとき[myDisplayedTable reloadData]は、メイン キューでこの操作を呼び出す必要があります。

dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });
于 2013-06-27T16:37:40.857 に答える