【问题标题】:How do I use CFArrayRef in Swift?如何在 Swift 中使用 CFArrayRef?
【发布时间】:2014-09-18 07:37:46
【问题描述】:

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

- (CFArrayRef)someMethod:(someType)someParameter;

我首先获取类的实例、调用方法并存储值:

var myInstance = MyClassWithThatMethod();
var cfArr = myInstance.someMethod(someValue);

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

var valueInArrayThatIWant = CFArrayGetValueAtIndex(cfArr, 0);

但是我收到错误Unmanaged<CFArray>' is not identical to 'CFArray'Unmanaged<CFArray> 到底是什么意思?

我查看了How to convert CFArray to Swift Array?,但我不需要将数组转换为 swift 数组(不过这样会很好)。我只需要能够从数组中获取值。

我也尝试过将CFArray 传递给in this answer 概述的函数的方法:

func doSomeStuffOnArray(myArray: NSArray) {

}

但是我在使用时遇到了类似的错误:

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

我使用CFArray是因为我需要存储CGPathRef的数组,而NSArray中无法存储。

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

【问题讨论】:

  • CGPathRef 转换为id 有助于Objective-C,但不确定Swift。
  • 你能用一个UIBezierPath,它可以包含一个CGPath,符合NSCoding,所以你应该可以把它放在NSArray中。
  • @Zaph 我考虑过,但这似乎使它变得比需要的更困难。
  • @duci9y CGPath 被创建并添加到 Objective-C 文件中的CFArray,所以它可能会起作用,就像 Zaph 所说的一样。但是我正在寻找一种在 Swift 中使用 CFArrayRef 的方法。
  • 当显而易见的解决方案是使用本机数组时,您为什么要使用CFArrayRef?有什么特别的原因吗?

标签: ios objective-c arrays swift


【解决方案1】:

如中所述 Working with Core Foundation Types,有两种可能的解决方案 你从你自己的函数中返回一个 Core Foundation 对象,该函数在 Swift 中导入:

  • CF_RETURNS_RETAINEDCF_RETURNS_NOT_RETAINED 注释函数。 在你的情况下:

    - (CFArrayRef)someMethod:(someType)someParameter CF_RETURNS_NOT_RETAINED;
    
  • 或者在 Swift 中使用takeUnretainedValue()takeRetainedValue() 将非托管对象转换为内存托管对象。在你的情况下:

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

【讨论】:

  • 这是一个很棒的发现,它解决了手头的问题。但是,从我的CFArrayGetValueAtIndex 调用返回的值是ConstUnsafePointer&lt;()&gt; 类型。知道如何将其转换为 CGPathRef 吗?我想我遇到了this problem
  • @SantaClaus:我尝试了一点,但找不到从 Swift 中的数组中提取 CGPathRef 的解决方案。使用包含 UIBezierPath 对象的 NSArray 可能会更好。
  • 是的。不久前,我将我的 Objective-C 代码转换为返回 UIBezierPath 对象的 NSArray。可惜我不能让CFArray 工作。
  • @MartinR 我需要在takeRetainedValue 之后手动调用release(我正在调用UTTypeCreateAllIdentifiersForTag(_:_:_:))吗?如果没有,Swift 是如何管理这块内存的?
  • @Alexander:不,你没有。在 takeRetainedValue 之后,ARC 会像对待任何其他引用类型一样对待对象,并在对象超出范围时向对象发送释放。
【解决方案2】:

Unmanaged 是实际 CF 值的包装器。 (有点像一个可选的。)它的存在是因为 ARC 无法通过查看 someMethod: 的声明来判断该方法是否保留了它返回的值。

您可以通过告诉 ARC 对其中的值使用什么内存管理策略来打开 Unmanaged。如果someMethod 在其返回值上调用CFRetain

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

如果没有:

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

完成此操作后,cfArrCFArray,因此您可以使用链接到的其他问题中的桥接技巧来像 Swift 数组一样访问它。

如果您拥有someMethod 的代码,您可以稍微更改一下以不需要它。有几种选择:

  • 使用CF_RETURNS_RETAINEDCF_RETURNS_NOT_RETAINED 进行注释以告诉编译器需要什么内存行为
  • 因为它是一个 ObjC 方法,所以桥接到NSArray 并返回——它会在 Swift 中自动变成一个[AnyObject] 数组。

【讨论】:

  • 将它桥接到NSArray 是否会产生任何不利的副作用,因为CFArray 包含CGPathRefs 不能包含在NSArray 中?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-26
  • 2015-09-21
  • 2021-04-05
  • 2017-08-05
  • 2014-10-26
  • 2018-12-12
  • 2021-05-15
相关资源
最近更新 更多