我有一个应用程序,它逐行绘制来自网络的图像数据。我想展示这个更新过程,而不仅仅是最终图像。
我绘制它的原始代码如下所示:
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-200 毫秒到它的一小部分)。然而,如果没有这个调用,由于某些竞争条件,事情会很快崩溃,这是合理的,因为我认为 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) ;
}
最佳答案
现在,您正在将 UI 的更新同步分派(dispatch)回主循环。这意味着图像数据的(大概)后台处理将不得不等待。
一般来说,我会建议异步分派(dispatch)(以避免让后台进程等待 UI 更新)。但是,在这种情况下,您可能也不想异步分派(dispatch)它(因为您最终可能会得到主队列的备份,而这些请求的传入速度快于它处理它们的速度)。
我建议将图像的重绘与处理下载数据的循环分离。您可以通过两种机制实现这一点,这两种机制都需要确保您的后台进程不将任何东西分派(dispatch)给主队列本身,而是:
在后台线程中更新像素缓冲区,但在将更新 UI 的主运行循环上配置
CADisplayLink
。显示链接类似于NSTimer
,只是它链接到 UI 的更新。使用
DISPATCH_SOURCE_TYPE_DATA_ADD
类型的调度源来跟踪您收到的像素数量,例如。同样,在后台线程中更新像素缓冲区,让它执行dispatch_source_merge_data
以更新此像素计数。然后你在主线程上有一个dispatch_source_set_event_handler
,监听这些合并事件。
这两种技术都允许您在后台线程中进行处理,以尽可能高的频率更新 UI,但不会冒将后台任务减慢到 UI 更新速度的风险,也不会因 UI 更新请求而积压主线程.
显然,请确保您从两个线程访问的任何对象都已正确同步。您需要确保主线程使用的数据不会同时被后台线程更改。
关于ios - 逐行绘制到位图上下文的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28967067/