2

カスタムUITableViewCellを作成します。

 SListViewCell * cell = nil;
//    cell = [listView dequeueReusableCellWithIdentifier:CELL];
if (!cell) {
    cell = [[[SListViewCell alloc] initWithReuseIdentifier:CELL] autorelease];
}
listView.separatorColor = [UIColor clearColor];
cell.backgroundColor = [UIColor clearColor];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UIButton* btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.tag = index;
[btn setFrame:CGRectMake(0, 0, 42, 42)];
//setBtnImage will download image from network. when the UIButton click it is will change button image 
[self setBtnImage:index btn:btn];
[btn addTarget:self action:@selector(typeTapped:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:btn];
return  cell;

typeTappedメソッド:

-(void)typeTapped:(id)sender
{
   UIButton* btn = (UIButton)sender;
   //download image from network in ohter thread and change button' image.
   NSThread * thread = [Thread alloc] initWith:@selecter(downloadImage:)....
   [thread start];
   [thread release];
}
//download image 
-(void)downloadImage:(UIButton*)btn....
{
  //download
  UIImage* image= ....
  //UITableView is not update
  //it is will update when i scroll tableview.
  [btn setImage:image ......];
}

したがって、他のスレッドでUITableViewCellを更新するにはどうすればよいですか(reloadDateを呼び出すと、完全に停止します)(テーブルビューをスクロールして更新できます)

4

2 に答える 2

6

ほとんどの処理はバックグラウンドで実行できますが、UIを更新するものはすべてメインスレッドで実行する必要があります。

バックグラウンド処理を実行してからUIを更新するには、Grand Central Dispatch(GCD)を使用して簡単に実行できます。

- (void)typeTapped:(id)sender
{
    UIButton* btn = (UIButton*)sender;
    // Use Grand Central Dispatch to do the processing in the background.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        // Do download operation here... Something like:
        NSData* imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://some_url.com/some.image"]];
        UIImage* image = [UIImage imageWithData:imageData];

        //Go back to the main thread to update the UI. this is very important!
        dispatch_async(dispatch_get_main_queue(), ^{
            [btn setImage:image forState:UIControlStateNormal];
        });
    });
}

でも。テーブルビューには、いくつかの落とし穴があります。

テーブルセルは再利用されます。これは、UITableViewCellの素敵なUIButtonが、ダウンロードが完了した後のUIButtonとは異なる可能性があることを意味します。これは同じオブジェクトですが、別の行のコンテンツを表示するように再構成されています。

このような場合、最善の策は、GCDを使用してNSArrayを更新するか、他のデータ構造がフィード元にあることを確認してから、テーブルビューにセルの更新を依頼することです。

//UITableViewDelegate内。

@implementation SomeViewController
{
  NSMutableArray* _tableData;
}

// ...

// Someone tapped on the cell.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        // Do download operation here... Something like:
        NSData* imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://some_url.com/some.image"]];
        UIImage* image = [UIImage imageWithData:imageData];
        if([_tableData count] < indexPath.row) {
            _tableData[indexPath.row] = image;
        }
        //Go back to the main thread to update the UI. this is very important!
        dispatch_async(dispatch_get_main_queue(), ^{
            [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        });
    });

}
于 2012-10-29T11:56:11.080 に答える
1

UIの更新は、メインスレッドでのみ発生します。別のスレッドでUITableViewCellを更新する必要はないと思います。

Apple docから:

アプリケーションのユーザーインターフェイスへの操作は、メインスレッドで行う必要があります。したがって、アプリケーションのメインスレッドで実行されているコードから常にUIViewクラスのメソッドを呼び出す必要があります。これが厳密に必要でない場合は、ビューオブジェクト自体を作成する場合のみですが、他のすべての操作はメインスレッドで行う必要があります。

于 2012-10-29T11:51:42.130 に答える