gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-28 21:49:08 24 4
gpt4 key购买 nike

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

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

 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com