在Swift中使用UnsafeMutablePointer作为适当大小的C数组在Obj-C中的替代品

20
我该如何与以前使用大小为C数组的swift函数进行交互?
我阅读了与C API交互,但仍无法弄清楚。 func getCoordinates(_ coords:UnsafeMutablePointer<CLLocationCoordinate2D>,range range:NSRange)的coords参数文档说明:“在输入时,您必须提供足够大以容纳所需坐标数的结构体的C数组。在输出上,此结构包含请求的坐标数据。”
我尝试了几种方法,最近的一种是:
var coordinates: UnsafeMutablePointer<CLLocationCoordinate2D> = nil
polyline.getCoordinates(&coordinates, range: NSMakeRange(0, polyline.pointCount))

我需要使用类似这样的东西吗:

var coordinates = UnsafeMutablePointer<CLLocationCoordinate2D>(calloc(1, UInt(polyline.pointCount)))

抓狂了...有什么想法吗?

你尝试过这个吗:var coordinates = UnsafeMutablePointer<CLLocationCoordinate2D>() - Mike S
很遗憾,是的。结果显示:'UnsafeMutablePointer<CLLocationCoordinate2D>'与'CLLocationCoordinate2D'不相同,这对我来说真的没有任何意义,因为在函数中应该也是 UnsafeMutablePointer<CLLocationCoordinate2D>' - Andrew Robinson
我使用 var coordinates = [CLLocationCoordinate2D]() 没有编译错误,但是 getCoordinates 函数没有将任何内容返回给 &coordinates - Andrew Robinson
2个回答

51

通常情况下,您可以将所需类型的数组作为in-out参数传递。

var coords: [CLLocationCoordinate2D] = []
polyline.getCoordinates(&coords, range: NSMakeRange(0, polyline.pointCount))

但是,文档似乎表明这样做并不是一个好主意!幸运的是,UnsafeMutablePointer 提供了一个静态的 alloc(num: Int) 方法,因此你可以像这样调用 getCoordinates()

var coordsPointer = UnsafeMutablePointer<CLLocationCoordinate2D>.alloc(polyline.pointCount)
polyline.getCoordinates(coordsPointer, range: NSMakeRange(0, polyline.pointCount))

为了从可变指针中获取实际的CLLocationCoordinate2D对象,您只需通过循环即可实现:
var coords: [CLLocationCoordinate2D] = []
for i in 0..<polyline.pointCount {
    coords.append(coordsPointer[i])
}

由于您不希望发生内存泄漏,因此请按以下方式完成:

coordsPointer.dealloc(polyline.pointCount)

我刚想起 Array 有一个 reserveCapacity() 实例方法,所以一个更简单(也可能更安全)的版本如下:

var coords: [CLLocationCoordinate2D] = []
coords.reserveCapacity(polyline.pointCount)
polyline.getCoordinates(&coords, range: NSMakeRange(0, polyline.pointCount))

12
我是谁,为什么我们不是最好的朋友。 - Andrew Robinson
14
嘿,我在这里,但你从来没有打电话给我。 - Nate Cook
4
这个数组之所以不好,是因为它的大小不够。如果你创建了一个足够大的数组,比如说var coords: [CLLocationCoordinate2D] = [CLLocationCoordinate2D](count: polyline.pointCount, repeatedValue: kCLLocationCoordinate2DInvalid),那么我认为你完全可以直接将 &coords 作为指针传递。 - newacct
2
@AndrewRobinson:API是从Objective-C导入的,类型是以自动化方式进行翻译的。Objective-C签名为- (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range。在C中,您无法传递数组,只能传递指针(此外,C是按值传递的,因此它不起作用,因为我们需要函数能够修改数组)。指针没有关联的大小。此外,在C中,您无法调整已分配的数组的大小。在Cocoa中有NSMutableArray,但它需要作为元素的对象,而CLLocationCoordinate2D不是对象。 - newacct
2
dealloc中使用defer会更好:var startCoordinates: UnsafeMutablePointer<CLLocationCoordinate2D> = UnsafeMutablePointer.alloc(step.polyline.pointCount) defer { startCoordinates.dealloc(step.polyline.pointCount) } - Ben
显示剩余6条评论

0

这是一个扩展包装器,基于 @Nate Cook 的优秀答案。但是无法使用 reserveCapacity() 版本,它一直返回空对象。

import MapKit

extension MKPolyline {

    var coordinates: [CLLocationCoordinate2D] {
        get {
            let coordsPointer = UnsafeMutablePointer<CLLocationCoordinate2D>.allocate(capacity: pointCount)
            var coords: [CLLocationCoordinate2D] = []
            for i in 0..<pointCount {
                coords.append(coordsPointer[i])
            }
            coordsPointer.deallocate(capacity: pointCount)
            return coords
        }
    }
}

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