任何人都可以阐明如何在 Swift 中对 Core Foundation 的 CFBinaryHeap 数据结构调用 CFBinaryHeapGetValues 吗?代码示例/示例对我有很大帮助。这是我目前的代码:
public class CountedColor : NSObject
{
public private(set) var count: Int
public private(set) var color: UIColor
public init(color: UIColor, colorCount: Int)
{
self.count = colorCount
self.color = color
super.init()
}
}
var callbacks = CFBinaryHeapCallBacks()
callbacks.compare = { (a,b,unused) in
let afoo : CountedColor = (a?.assumingMemoryBound(to: CountedColor.self).pointee)!
let bfoo : CountedColor = (b?.assumingMemoryBound(to: CountedColor.self).pointee)!
if ( afoo.count == bfoo.count ) { return CFComparisonResult.compareEqualTo }
if ( afoo.count > bfoo.count ) { return CFComparisonResult.compareGreaterThan }
return CFComparisonResult.compareLessThan
}
let callbackPointer = UnsafeMutablePointer<CFBinaryHeapCallBacks>.allocate(capacity: 1)
callbackPointer.initialize(to: callbacks)
var bh = CFBinaryHeapCreate(nil, 0, callbackPointer, nil)
var fooPointer : UnsafeMutablePointer<CountedColor>!
fooPointer = UnsafeMutablePointer<CountedColor>.allocate(capacity: 1)
fooPointer.initialize(to: CountedColor(color: UIColor.blue, colorCount: 72))
CFBinaryHeapAddValue(bh, fooPointer)
fooPointer = UnsafeMutablePointer<CountedColor>.allocate(capacity: 1)
fooPointer.initialize(to: CountedColor(color: UIColor.red, colorCount: 99))
CFBinaryHeapAddValue(bh, fooPointer)
var elements = [CountedColor](repeating: CountedColor(color: UIColor.white, colorCount: 0), count: 2)
var elementPtr = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 1)
elementPtr.initialize(to: elements)
CFBinaryHeapGetValues(bh, elementPtr)
var returnedValues: UnsafePointer<[CountedColor]> = (elementPtr.pointee?.assumingMemoryBound(to: [CountedColor].self))!
print(elementPtr.pointee?.assumingMemoryBound(to: CountedColor.self).pointee.count)
print(elementPtr.pointee?.assumingMemoryBound(to: CountedColor.self).pointee.color)
let values = returnedValues.pointee
^^如果您查看上面的最后三行,代码在最后一行失败,我得到一个 EXC_BAD_ACCESS。我很困惑为什么因为上面的两个打印语句确实有效。我能够验证函数返回的 C 数组中的第一个对象确实是计数为 72 的较小颜色。所以这意味着我传入的数组正在用值更新,但是当我尝试获取句柄时在阵列上通过访问 pointee 事情变得一团糟。起初我认为这是一个内存管理问题,但在阅读了桥接在 Swift 中的工作原理后,我不确定情况是否如此,尤其是因为这是一个带注释的 CoreFoundation API。
最佳答案
在您的代码中:
CFBinaryHeapAddValue(bh, fooPointer)
您正在传递一个 UnsafeMutablePointer<CountedColor>
, 两次。
(元素的数量影响很多部分。)
因此,当调用 CFBinaryHeapGetValues(bh, elementPtr)
时, 你需要为 C-array 保留一个区域,它可以包含两个 UnsafeMutablePointer<CountedColor>
你应该这样写:
var elementPtr = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 2) //<- You need to allocate a region for two elements
elementPtr.initialize(to: nil, count: 2) //<- The content is overwritten, initial values can be nil
CFBinaryHeapGetValues(bh, elementPtr)
还有这段代码:
var returnedValues: UnsafePointer<[CountedColor]> = (elementPtr.pointee?.assumingMemoryBound(to: [CountedColor].self))!
正如我上面写的,结果存储在 elementPtr
指向的区域中是 UnsafeMutablePointer<CountedColor>
s,不是 UnsafePointer<[CountedColor]>
.
elementPtr.pointee
检索第一个 UnsafeMutablePointer<CountedColor>
,所以你的两个print
语句有效,但这并不意味着 returnedValues
您的代码包含您期望的内容。
处理 C 数组的一个好方法是创建一个 UnsafeBufferPointer
.
let returnedValues = UnsafeBufferPointer(start: elementPtr, count: 2)
UnsafeBufferPointer
用作 Collection 类型,因此您可以轻松地将其转换为 Array
.
let values = returnedValues.map{$0!.load(as: CountedColor.self)}
请不要忘记 deinitialize
和 deallocate
allocate
编辑区域。
要做到这一点,您需要保留所有分配的指针及其计数。因此,您可能需要将代码的某些部分更改为:
var fooPointer : UnsafeMutablePointer<CountedColor>!
fooPointer = UnsafeMutablePointer<CountedColor>.allocate(capacity: 1)
fooPointer.initialize(to: CountedColor(color: UIColor.blue, colorCount: 72))
CFBinaryHeapAddValue(bh, fooPointer)
var barPointer : UnsafeMutablePointer<CountedColor>!
barPointer = UnsafeMutablePointer<CountedColor>.allocate(capacity: 1)
barPointer.initialize(to: CountedColor(color: UIColor.red, colorCount: 99))
CFBinaryHeapAddValue(bh, barPointer)
然后在使用完 CFBinaryHeap ( bh
)...
elementPtr.deinitialize(count: 2)
elementPtr.deallocate(capacity: 2)
barPointer.deinitialize()
barPointer.deallocate(capacity: 1)
fooPointer.deinitialize()
fooPointer.deallocate(capacity: 1)
您可能想要添加任意数量的 CountedColor
s 到 CFBinaryHeap,在这种情况下,您可以这样写:
let colors = [
CountedColor(color: UIColor.blue, colorCount: 72),
CountedColor(color: UIColor.red, colorCount: 99),
//...
]
var fooPointer : UnsafeMutablePointer<CountedColor>!
fooPointer = UnsafeMutablePointer<CountedColor>.allocate(capacity: colors.count)
fooPointer.initialize(from: colors)
for i in colors.indices {
CFBinaryHeapAddValue(bh, fooPointer+i)
}
(您可能需要将我代码中所有 count:
或 capacity:
的 2
更改为 colors.count
。)
然后..
elementPtr.deinitialize(count: colors.count)
elementPtr.deallocate(capacity: colors.count)
fooPointer.deinitialize(count: colors.count)
fooPointer.deallocate(capacity: colors.count)
无论如何,匹配initialize
和 deinitialize
, allocate
和 deallocate
.
你可能会在 Swift 标准库中找到一些有用的类型来改进代码,但一次学习太多可能不是一个好习惯......
关于arrays - 如何正确调用 CFBinaryHeapGetValues() 并在 Swift 中解析生成的 C 数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40966912/