我有以下代码尝试异步加载tableview中的一行缩略图:
for (int i = 0; i < totalThumbnails; i++)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
__block GraphicView *graphicView;
__block Graphic *graphic;
dispatch_async(dispatch_get_main_queue(),
^{
graphicView = [[tableViewCell.contentView.subviews objectAtIndex:i] retain];
graphic = [[self.thumbnailCache objectForKey: [NSNumber numberWithInt:startingThumbnailIndex + i]] retain];
if (!graphic)
{
graphic = [[self graphicWithType:startingThumbnailIndex + i] retain];
[self.thumbnailCache setObject: graphic forKey:[NSNumber numberWithInt:startingThumbnailIndex + i]];
}
[graphicView setGraphic:graphic maximumDimension:self.cellDimension];
});
[graphicView setNeedsDisplay];
dispatch_async(dispatch_get_main_queue(),
^{
CGRect graphicViewFrame = graphicView.frame;
graphicViewFrame.origin.x = ((self.cellDimension - graphicViewFrame.size.width) / 2) + (i * self.cellDimension);
graphicViewFrame.origin.y = (self.cellDimension - graphicViewFrame.size.height) / 2;
graphicView.frame = graphicViewFrame;
});
[graphicView release];
[graphic release];
});
}
然而,当我运行代码时,我在这一行得到了一个错误的访问:[graphicView setNeedsDisplay];
值得一提的是,当我设置这样的代码时,代码工作正常:
for (int i = 0; i < totalThumbnails; i++)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
dispatch_async(dispatch_get_main_queue(),
^{
//put all the code here
});
}
它工作正常,UITableView
在第一次调用时异步加载,但滚动仍然非常不稳定。
所以我想让第一部分代码工作,这样我就可以在全局线程而不是主线程中完成绘图(我假设它会修复不连贯的滚动?)。
由于iOS4绘图能够异步完成,所以我不相信这是问题所在。我可能会误用__Block
类型?
任何人都知道如何让它发挥作用?
答案 0 :(得分:2)
你完全误解了如何使用GCD。看看你的代码:
__block GraphicView *graphicView;
此处的变量未初始化为nil。发送消息是不安全的。
__block Graphic *graphic;
dispatch_async(dispatch_get_main_queue(),
^{
//statements
});
此处的发送声明立即返回。系统可以让您在另一个线程上关闭此任务。在执行上述陈述之前或同时,我们继续执行下一行执行......
[graphicView setNeedsDisplay];
此时,您的调度声明可能已经或可能没有初始化图形视图。很可能不是因为没有时间。由于它仍未初始化,因此指向随机存储器,因此尝试向其发送消息会导致EXC_BAD_ACCESS。
如果你想异步绘制单元格内容(或预渲染图像或其他任何内容。)我会一直推荐观看WWDC 2012会话211“在iOS上构建并发用户界面”。他们几乎完全按照你的目的去做,并解释你可能遇到的所有陷阱。
答案 1 :(得分:0)
我认为问题是因为您试图在工作线程上重新绘制UIView
。你应该移动它:
[graphicView setNeedsDisplay];
到主队列。