gpt4 book ai didi

ios - 我可以从多个线程绘制到同一个 CGContextRef 吗?

转载 作者:可可西里 更新时间:2023-11-01 00:53:37 27 4
gpt4 key购买 nike

我正在制作一个应用程序,我想在其中绘制很多形状 - 圆圈、框、线等。数以百万计。

为了测试它的性能,我拼凑了这个简单的 UIView。请注意,功劳已到 - 我的灵感来自 this project .

import UIKit

let qkeyString = "label" as NSString
var QKEY = qkeyString.UTF8String
let qvalString = "com.hanssjunnesson.Draw" as NSString
var QVAL = qvalString.UTF8String

public class RenderImageView: UIView {

var bitmapContext: CGContext?

let drawQueue: dispatch_queue_attr_t = {
let q = dispatch_queue_create(QVAL, nil)
dispatch_queue_set_specific(q, QKEY, &QVAL, nil)

return q
}()

public override init() {
super.init()

render()
}

required public init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)

render()
}

override required public init(frame: CGRect) {
super.init(frame: frame)

render()
}

public override func drawRect(rect: CGRect) {
if let bitmapContext = self.bitmapContext {
let context = UIGraphicsGetCurrentContext()
let image = CGBitmapContextCreateImage(bitmapContext)
CGContextDrawImage(context, self.bounds, image)
}
}

private func render() {
dispatch_async(drawQueue) {
let startDate = NSDate()

let bounds = self.bounds
UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)
let context = UIGraphicsGetCurrentContext()
self.bitmapContext = context

CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
CGContextFillRect(context, bounds)

CGContextSetFillColorWithColor(context, UIColor(red: 0.15, green: 0.4, blue: 0.8, alpha: 1.0).CGColor)

for i in 1...1000000 {
CGContextFillEllipseInRect(context, bounds)
}

UIGraphicsEndImageContext()

self.setNeedsDisplay()

let benchmark = startDate.timeIntervalSinceNow
println("Rendering took: \(-benchmark*1000) Ms")
}
}
}

这很好用。在我的 iOS 模拟器上,只需一分多钟的时间就可以在彼此之上绘制一百万个圆圈。

我想加快速度,所以我尝试从多个线程绘制到位图上下文。

let group = dispatch_group_create()
for i in 1...100 {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
dispatch_group_enter(group)

CGContextFillEllipseInRect(context, bounds)

dispatch_group_leave(group)
}
}

dispatch_group_wait(group, DISPATCH_TIME_FOREVER)

然而,这并没有奏效。我在调用 CGContextFillEllipseInRect(context, bounds) 时得到一个 EXC_BAD_ACCESS

在后台线程中绘制到 CGContext 似乎没问题,只要它是创建它的同一线程。

有人知道如何让它发挥作用吗?

最佳答案

1) 你实际上并不是在等待你创建的组完成——dispatch_group_wait 将在任何 block 被执行之前在该代码中被调用,所以进入/离开他们内部的电话不会有任何影响。请改用 dispatch_group_async(见下文)。

2) 您不能同时从两个不同的线程绘制到 CGContext - 如果您在绘制循环中添加 println,就会看到这一点。它会工作几次,结果各不相同,但最终你会遇到错误。

let group = dispatch_group_create()
for i in 1...10 {
dispatch_group_async(group, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
for j in 1...100 {
println("i:\(i), j:\(j)")
CGContextFillEllipseInRect(context, bounds)
}
}
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER)

示例输出:

iiii::::4123,,,,    jjjj::::1111



ii:1, j:2
:5, j:1
i:6, j:1
EXC_BAD_ACCESS

对此的唯一解决方案是跳回到单个线程上进行绘图,但这会破坏您尝试以任何方式执行的操作。如果您必须进行大量计算才能决定绘制什么,这可能发生在单独的线程上,但绘制到 CGContext 本身并不是线程安全的。

关于ios - 我可以从多个线程绘制到同一个 CGContextRef 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27064119/

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