ios - 逐行绘制到位图上下文的有效方法

标签 ios xcode performance bitmap core-graphics

我有一个应用程序,它逐行绘制来自网络的图像数据。我想展示这个更新过程,而不仅仅是最终图像。

我绘制它的原始代码如下所示:

 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)给主队列本身,而是:

  1. 在后台线程中更新像素缓冲区,但在将更新 UI 的主运行循环上配置 CADisplayLink。显示链接类似于 NSTimer,只是它链接到 UI 的更新。

  2. 使用 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/

相关文章:

objective-c - iOS 应用程序崩溃,符号化日志不透明

iphone - 如何在 Objective C 中使用 strlen 查找字符串长度

swift - 如何在 Xcode 8 中显示类型层次结构?

c# - 为什么在 C# 中使用结构 Vector3I 而不是三个整数要慢得多?

iOS 8 旋转方法弃用 - 向后兼容性

iphone - iOS 分页控件(导航)

ios - NSBlockOperation 在执行前不等待依赖

python - 用于访问 Pandas 中的列的括号表示法和点表示法之间的速度差异

java - 如何在NetBeans平台应用程序中更快地显示Java3D图像?

iphone - 数据模型中的 Char* 内存被回收?