Ken Aspeslagh 对于从辅助线程进行绘制有些不正确(他是正确的,这通常是一个坏主意)。从我所看到的你的代码来看,你没有一个很好的用例来在辅助线程上绘图。您能解释一下为什么要这样做吗?
你自己已经发现了setCanDrawConcurrently:
其中明确谈到调用drawRect:
来自后台线程。请注意,视图窗口必须具有allowsConcurrentViewDrawing
设置为 YES 才能正常工作(这是默认值)。
苹果自己的可可绘图指南 https://developer.apple.com/library/mac/documentation/cocoa/conceptual/CocoaDrawingGuide/GraphicsContexts/GraphicsContexts.html有一个关于从辅助线程绘图的部分。我强调了一些我认为与您相关的部分。
应用程序工具包为每个窗口和线程组合维护一个独特的图形上下文。由于每个线程对于给定窗口都有自己的图形上下文对象,因此可以使用辅助线程来绘制该窗口。不过,也有一些注意事项。
在窗口的正常更新周期中,所有绘图请求都会发送到应用程序的主线程进行处理。当用户事件触发用户界面的更改时,就会发生正常的更新周期。在这种情况下,您可以从应用程序的主线程调用 setNeedsDisplay: 或 setNeedsDisplayInRect: 方法(或显示方法系列)以使视图中需要重绘的部分无效。您不应从任何辅助线程调用这些方法。
如果要从辅助线程更新窗口或视图,则必须手动将焦点锁定在窗口或视图上并自行启动绘制。锁定焦点会配置该窗口的图形上下文的绘图环境。锁定后,您可以配置绘图环境,照常发出绘图命令,然后将图形上下文的内容刷新到窗口缓冲区。
为了定期在辅助线程上绘图,您必须自己通知该线程。发送定期通知的最简单方法是使用 NSTimer 或 NSAnimation 对象。有关如何制作内容动画的更多信息,请参阅“高级绘图技术”。
Cocoa 线程编程指南 https://developer.apple.com/library/mac/documentation/cocoa/conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html还这样说:
如果要使用线程绘制视图,请将所有绘制代码放在 NSView 的 lockFocusIfCanDraw 和unlockFocus 方法之间
顺便说一句,GCD 块调用可能是一种比在后台执行少量操作更好的方法NSThread
.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// you can put each of these calls in their own queue if you want
[self DrawText];
[self DrawRectangle];
[self DrawGradient];
});
但是,这可能与您的问题无关;我提到它只是因为我认为使用 GCD 队列会更好地为你服务。