在iOS上的后台线程中绘制图形

6
我有一个视图,其中有一些非常复杂的绘图逻辑(它是从 GIS 数据绘制的地图视图)。在主线程上进行此绘图会锁定 UI 并使应用程序无响应。我想将绘图移到后台线程中,例如使用 NSOperation。
最佳结构方式是什么?
我目前正在绘制到离屏 CGContext,然后将其转换为 CGImageRef,然后将其发送到视图以在主线程上进行 blit。不幸的是,这会占用很多内存,并且似乎 GPU 加速不再使用,因为它要慢得多。有没有一种直接从后台线程绘制到视图的方法?我知道 UIKit 不支持多线程,但也许有一些方法可以在绘制时锁定视图?
2个回答

8
在iOS 4.0之后,绘图是线程安全的。你可能需要自己创建一个CGContext,但没有理由不在后台线程中绘制。
尽管如此,大多数UIKit操作并非线程安全的。如果你需要执行这些操作,可以在后台线程中准备好,然后在需要时使用performOnMainThread。甚至还有waitUntilDone。不过,据说应该使用NSOperationNSOperationQueue

2
似乎有很多人对此感到困惑,但截至iOS 4.0,使用UIKit进行绘图是线程安全的。这是官方声明:http://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html(搜索“thread”)。 - Jon Tirsen

0

我在 iPhone 上从未遇到过这种情况,但在 Mac 上曾经遇到过类似的问题。

  1. 使用 CGLayer 委托离线上下文的绘图活动。
  2. 尝试为当前 NSRunLoop 添加计时器,并在定时间隔内执行您的图形命令。它应该看起来像这样...

...

kRenderFPS 25.0 //This is Maximum value

renderTimer = [[NSTimer timerWithTimeInterval:(1.0 / (NSTimeInterval)kRenderFPS) target:viewobject selector:@selector(RenderUI:) userInfo:nil repeats:YES] retain];


[[NSRunLoop currentRunLoop] addTimer:renderTimer forMode:NSDefaultRunLoopMode];


[[NSRunLoop currentRunLoop] addTimer:renderTimer forMode:NSModalPanelRunLoopMode];


[[NSRunLoop currentRunLoop] addTimer:renderTimer forMode:NSEventTrackingRunLoopMode];

//In view class
-(void)RenderUI:(id)param
{
    [self setNeedsDisplayInRect:[self bounds]];
}

这应该能解决问题。

同时尝试对进程进行采样,并检查谁在消耗CPU。这将使UI响应迅速且非常快。

你提到的性能问题可能是由其他原因引起的。尝试对CPU进行采样,它将为您提供有关实际占用CPU的信息。


1
不。CGLayer。http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CGLayer/Reference/reference.html - RLT
你尝试过哪种风格?是 CGLayer 还是 NSRunLoop 还是两者都用了?使用 CGLayer 来委托离屏绘制,NSRunLoop 则用于在定时间隔上执行绘制命令。 - RLT
我同时使用了CGLayer和NSRunLoop。现在我正在尝试在后台线程中使用CGLayer和NSOperation。虽然UI现在很流畅,但是我在后台线程中遇到了非常糟糕的性能问题。 - Jon Tirsen
我会在我的回答中添加更多细节。 - RLT
使用CGLayer对象可以提高性能,特别是当您需要捕获一块需要重复标记的绘图(使用相同的比例因子和方向)时。Quartz可以将CGLayer对象缓存到视频卡中,因此将CGLayer绘制到目标上要比从位图上下文构造等效图像的渲染速度快得多。 - RLT
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接