日々精進

新しく学んだことを書き留めていきます

バックグラウンドスレッドでUITableViewを更新する

重い検索処理をバックグラウンドスレッドで実行して、その結果をUITableViewに反映させようとしてはまった。
最初は以下のようにしていたが、これは間違い。

- (void)searchStocks:(id)param{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    while (TRUE) {
        if (self.thread.isCancelled) {
            break;
        }
        if (self.keyWords != nil) {
            StockSearchCriteria *criteria = [[StockSearchCriteria alloc] initWithKeyWords:self.keyWords];
            self.stockSearchPopoverController.tableViewController.stocks = [StockContainer findByCriteria:criteria];
            [self.stockSearchPopoverController.tableViewController.tableView reloadData];
            [self.stockSearchPopoverController.tableViewController.tableView performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO ];
            self.keyWords = nil;
        }
    }
    [pool release];
}

正しくは以下。

- (void)searchStocks:(id)param{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    while (TRUE) {
        if (self.thread.isCancelled) {
            break;
        }
        if (self.keyWords != nil) {
            StockSearchCriteria *criteria = [[StockSearchCriteria alloc] initWithKeyWords:self.keyWords];
            self.stockSearchPopoverController.tableViewController.stocks = [StockContainer findByCriteria:criteria];
            [self.stockSearchPopoverController.tableViewController.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO ];
            self.keyWords = nil;
        }
    }
    [pool release];
}

ポイントは以下。
・UITableViewのreloadDataはメインスレッドで実行しないといけない。そうしないとtableView:cellForRowAtIndexPathが実行されない。
・reloadDataを実行したらsetNeedsDisplayも実行されるっぽい。