CFAttributedString线程安全

时间:2017-10-11 20:22:15

标签: swift multithreading core-foundation

此代码是否显示CFAttributedString不是线程安全的?或者我在设置中做错了什么?

我认为CFAttributedString可以安全地从多个线程中读取,但是每隔几次运行就会看到此代码中的崩溃。

@IBAction func testIt(_ sender: Any?) {
    let testString = "Hello world! Lets make this a bit longerrrrrrrrrrrrrrrr." as CFString
    let testStringLength = CFStringGetLength(testString)

    let testAttributedString = CFAttributedStringCreateMutable(kCFAllocatorDefault, testStringLength)
    CFAttributedStringReplaceString(testAttributedString, CFRange(location: 0, length: 0), testString)
    CFAttributedStringEndEditing(testAttributedString)
    for i in 0..<testStringLength {
        let range = CFRange(location: i, length: 1)
        let keyAndValue = "\(i)" as CFString
        CFAttributedStringSetAttribute(testAttributedString, range, keyAndValue, keyAndValue)
    }

    let immutableTestAttributedString = CFAttributedStringCreateCopy(kCFAllocatorDefault, testAttributedString)
    DispatchQueue.concurrentPerform(iterations: 100) { _ in
        var index: CFIndex = 0
        var effectiveRange: CFRange = CFRange(location: 0, length: 0)
        while index < testStringLength {
            // Crash happens here EXC_BAD_ACCESS (code=1, address=0x24)
            let _ = CFAttributedStringGetAttributes(immutableTestAttributedString, index, &effectiveRange)
            index = effectiveRange.location + effectiveRange.length
        }
    }
}

1 个答案:

答案 0 :(得分:1)

let testString = "Hello world! Lets make this a bit longerrrrrrrrrrrrrrrr." as CFString

这是一个伪装成CFString的Swift字符串,它大约是两层间接,并在内部调用一个非常不同的代码路径(无论是否仍然有效,在你和{{{}之间3}})。

尝试创建一个合适的CFString并查看它是否按预期方式工作。

var bytes = Array("Hello world! Lets make this a bit longerrrrrrrrrrrrrrrr.".utf16)
let testString = CFStringCreateWithCharacters(nil, &bytes, bytes.count)

(当然我强烈建议在NSAttributedString而不是CFAttributedString中完成所有这些工作.Swift-&gt; Foundation桥接更简单,并且与Swift-&gt; Foundation-相比,不断使用&gt; CoreFoundation桥接。这可能只是桥接中的一个错误,但如果你避开它,你的世界仍然会变得容易多了。)

虽然我无法使用纯CFString重现问题,但这绝对不是线程安全的。 CoreFoundation是开源的(排序......,但足够用于此目的),因此您可以自己查看代码。最终CFAttributedStringGetAttributes调用radar,它会更新内部缓存并且没有锁定。我没有在docs中看到任何承诺这是线程安全的东西。