我做一个自定义的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它会下降,死机)(我可以滚动tableview中进行更新)
你可以完成大部分的处理在更新了UI主线程上发生的背景,但任何事情。
这样做后台处理,然后更新UI可以很容易地使用大中央调度(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可能不是你认为它是一旦下载完成的一个。 这是同一个对象,但已被重新配置,以显示来自另一行的内容。
对于这些情况下,最好的办法是使用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];
});
});
}
任何用户界面的更新只能在主线程上发生。 我不认为你应该在另一个线程更新的UITableViewCell。
从苹果的文档:
操作您的应用程序的用户界面必须在主线程上发生。 因此,你应该始终调用UIView类从代码中应用程序的主线程运行的方法。 这可能不是绝对必要的唯一的一次是在创建视图对象本身时,但所有其他的操作应在主线程上发生。