我有一个应用程序,它从网络进入时逐行绘制图像数据。我想显示这个更新过程,而不仅仅是最终图像。
我绘制此内容的原始代码如下所示:
dispatch_sync(dispatch_get_main_queue(),^(void){
for (int i=0;i<len; i = i+3)
{
float r = 1.0*byteData[i]/256;
float g = 1.0*byteData[i+1]/256;
float b = 1.0*byteData[i+2]/256;
CGContextSetRGBFillColor(myView->bitmapContext, r,g,b, 1.0f) ;
CGContextFillRect (g_myView->bitmapContext, CGRectMake(y, x, 1.0f, 1.0f)) ;
x++;
}
});
这很好但我发现删除dispatch_sync()会使性能更好(从大约100-200ms到一小部分)。但是如果没有这个调用,由于某些竞争条件,事情会很快崩溃,这是合理的,因为我认为应始终从主线程更新UI。
为了提高性能并保持正确,我的策略是创建一个临时位图上下文,将整行写入,然后在过程结束时安全地将该位图写入我的主位图。
代码如下所示:
CGContextRef context = [myView createCustomBitmapContextWithSize: CGSizeMake(1024.0f, 1.0f)] ;
for (int i=0;i<len; i = i+3)
{
float r = 1.0*byteData[i]/256;
float g = 1.0*byteData[i+1]/256;
float b = 1.0*byteData[i+2]/256;
CGContextSetRGBFillColor(context, r,g,b, 1.0f) ;
CGContextFillRect (context, CGRectMake(y, 0, 1.0f, 1.0f)) ;
x++;
}
dispatch_sync(dispatch_get_main_queue(),^(void){
CGImageRef image = CGBitmapContextCreateImage(context);
CGContextDrawImage(myView->bitmapContext, CGRectMake(0,x,1024.0f,1.0f), image);
});
这个问题的第一个问题是它根本没有呈现,所以我可能错误地使用了API。但是我检查了在接近结束时对CGBitmapContextCreateImage()的调用只需要大约100毫秒左右,所以即使我得到渲染它也不会有太大帮助。
有人可以帮我理解更适合的更新过程吗?
我认为我实际绘制到屏幕的方式可能是相关的,所以我也会显示我的drawRect:函数。
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext() ;
CGImageRef myImage = CGBitmapContextCreateImage(bitmapContext) ;
CGContextDrawImage(context, rect, myImage) ;
CGImageRelease(myImage) ;
}
答案 0 :(得分:2)
现在,您同步将UI的更新调度回主循环。这意味着图像数据的(可能)背景处理将不得不等待。
通常,我建议异步调度(以避免让后台进程等待UI更新)。但是,在这种情况下,您可能不想异步调度它(因为您可能最终得到主队列备份请求的速度超过它可以处理它们的请求)。
我建议将重新绘制图像与您处理下载数据的循环分离。您可以通过两种机制实现这一目标,这两种机制都需要确保您的后台进程不将任何内容发送到主队列本身,而是:
在后台线程中更新像素缓冲区,但在主运行循环上配置CADisplayLink
将更新UI。显示链接类似于NSTimer
,但它与UI的更新相关联。
例如,使用DISPATCH_SOURCE_TYPE_DATA_ADD
类型的调度源来跟踪您已收到的像素数。再次,更新后台线程中的像素缓冲区,让它执行dispatch_source_merge_data
来更新此像素数。然后你在主线程上有dispatch_source_set_event_handler
,听这些合并事件。
这两种技术都允许您在后台线程中进行处理,以尽可能高的频率更新UI,但不会冒着将后台任务降低到UI更新速度的风险,也不会冒着使用UI更新请求对主线程进行积压的风险
显然,请确保从两个线程访问的任何对象都已正确同步。您需要确保主线程使用的数据不会被后台线程同时变更。