我该如何在Swift中使用CFArrayRef?

4

我在Swift项目中通过桥接头文件使用了一个Objective-C类。该方法的签名看起来像这样:

- (CFArrayRef)someMethod:(someType)someParameter;

我先获取该类的实例,调用方法并保存值:
var myInstance = MyClassWithThatMethod();
var cfArr = myInstance.someMethod(someValue);

然后尝试从数组中获取一个值:

var valueInArrayThatIWant = CFArrayGetValueAtIndex(cfArr, 0);

然而我遇到了错误Unmanaged<CFArray>CFArray不相同。这里的Unmanaged<CFArray>是什么意思呢?
我查看了如何将CFArray转换为Swift Array?,但我并不需要将数组转换为Swift数组(虽然这样做也不错)。我只需要能够从数组中获取值。
我还尝试了将CFArray传递到函数中的方法,这在这个答案中有说明:
func doSomeStuffOnArray(myArray: NSArray) {

}

然而,当我使用它时,我得到了类似的错误:

doSomeStuffOnArray(cfArr); // Unmanaged<CFArray>' is not identical to 'NSArray'

我正在使用CFArray,因为我需要存储一个CGPathRef数组,而这个数组无法存储在NSArray中。

那么我应该如何在Swift中使用CFArray


CGPathRef 强制转换为 id 在 Objective-C 中很有帮助,但不确定在 Swift 中是否适用。 - duci9y
你可以使用一个 UIBezierPath,它可以包含一个 CGPath,并符合 NSCoding 协议,因此你应该能够将其放入一个 NSArray 中。 - zaph
@Zaph 我考虑过那个,但似乎比必要的更加困难。 - Andrew
@duci9y CGPath是在Objective-C文件中创建并添加到CFArray中的,因此它可能有效,就像Zaph所说的那样。然而,我正在寻找一种在Swift中使用CFArrayRef的方法。 - Andrew
你为什么要使用 CFArrayRef,而不是使用本地数组作为明显的解决方案呢?有特别的原因吗? - duci9y
显示剩余2条评论
2个回答

8

正如在与Core Foundation类型一起工作中所解释的那样,当您从自己导入到Swift的函数返回一个Core Foundation对象时,有两种可能的解决方案:

  • Annotate the function with CF_RETURNS_RETAINED or CF_RETURNS_NOT_RETAINED. In your case:

    - (CFArrayRef)someMethod:(someType)someParameter CF_RETURNS_NOT_RETAINED;
    
  • Or convert the unmanaged object to a memory managed object with takeUnretainedValue() or takeRetainedValue() in Swift. In your case:

    var cfArr = myInstance.someMethod(someValue).takeUnretainedValue()
    

这是一个很好的发现,它解决了手头的问题。然而,从我的CFArrayGetValueAtIndex调用返回的值的类型是ConstUnsafePointer<()>。有什么办法可以将其转换为CGPathRef吗?我想我遇到了这个问题 - Andrew
@SantaClaus:我尝试了一下,但无法找到从Swift数组中提取CGPathRef的解决方案。您最好使用包含UIBezierPath对象的NSArray。 - Martin R
是的。我刚刚将我的 Objective-C 代码转换为返回一个 NSArrayUIBezierPath 对象。可惜我无法让 CFArray 工作。 - Andrew
@MartinR 我需要在 takeRetainedValue 后手动调用 release 吗?(我正在调用 UTTypeCreateAllIdentifiersForTag(_:_:_:))如果不需要,Swift 是如何管理这个内存的? - Alexander
@Alexander:不需要。在 takeRetainedValue 之后,对象就像任何其他引用类型一样由 ARC 处理,并且当它超出范围时会向对象发送释放消息。 - Martin R
@MartinR 哦,我懂了。你知道有哪些资源可以更详细地介绍Swift中这些核心基础类型的确切工作原理吗? - Alexander

1
一个Unmanaged是对实际CF值的包装器。(有点像可选项。)它存在的原因是ARC无法从someMethod:的声明中看出该方法是否保留了它返回的值。
您可以通过告诉ARC内部值使用什么内存管理策略来解开Unmanaged。如果someMethod在其返回值上调用CFRetain:
let cfArr = myInstance.someMethod(someValue).takeRetainedValue()

如果它不这样做:

let cfArr = myInstance.someMethod(someValue).takeUnretainedValue()

在这之后,cfArr是一个CFArray,因此您可以使用其他链接问题中的桥接技巧来访问它,就像访问Swift数组一样。如果您拥有someMethod的代码,您可以稍微更改一下以不需要它。有几个选项可供选择:
  • 使用CF_RETURNS_RETAINEDCF_RETURNS_NOT_RETAINED进行注释,告诉编译器所需的内存行为
  • 由于它是一个ObjC方法,因此将其桥接到NSArray并返回它--它将自动成为Swift中的[AnyObject]数组。

将其桥接到NSArray是否会产生任何不良副作用,因为CFArray包含无法包含在NSArray中的CGPathRef - Andrew

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