UnsafeMutablePointer in swift as replacement for properly sized C Array in Obj-C

Andrew Robinson picture Andrew Robinson · Aug 29, 2014 · Viewed 12.5k times · Source

How can I interact with functions in swift that used to take sized C arrays?

I read through Interacting with C APIS and still can't figure this out.

The documentation for the coords parameter of func getCoordinates(_ coords:UnsafeMutablePointer<CLLocationCoordinate2D>,range range: NSRange) states: "On input, you must provide a C array of structures large enough to hold the desired number of coordinates. On output, this structure contains the requested coordinate data."

I tried several things, most recently:

var coordinates: UnsafeMutablePointer<CLLocationCoordinate2D> = nil
polyline.getCoordinates(&coordinates, range: NSMakeRange(0, polyline.pointCount))

Would I have to use something like:

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

Pulling my hair out here... any thoughts?

Answer

Nate Cook picture Nate Cook · Aug 29, 2014

Normally you can just pass an array of the required type as an in-out parameter, aka

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

but that documentation makes it seem like a bad idea! Luckily, UnsafeMutablePointer provides a static alloc(num: Int) method, so you can call getCoordinates() like this:

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

To get the actual CLLocationCoordinate2D objects out of the mutable pointer, you should be able to just loop through:

var coords: [CLLocationCoordinate2D] = []
for i in 0..<polyline.pointCount {
    coords.append(coordsPointer[i])
}

And since you don't want a memory leak, finish up like so:

coordsPointer.dealloc(polyline.pointCount)

Just remembered Array has a reserveCapacity() instance method, so a much simpler (and probably safer) version of this would be:

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