UnsafeMutablePointer в быстрой замене для C-массива с соответствующим размером C в Obj-C

Как я могу взаимодействовать с функциями в swift, которые используются для получения массивов C размера?

Я прочитал Взаимодействие с C APIS и до сих пор не могу понять этого.

В документации для параметра coords параметра func getCoordinates(_ coords:UnsafeMutablePointer<CLLocationCoordinate2D>,range range: NSRange) указано: "На входе вы должны предоставить массив C структур, достаточно больших, чтобы удерживать требуемое количество координат. На выходе эта структура содержит запрошенные координаты".

Я пробовал несколько вещей, совсем недавно:

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

Должен ли я использовать что-то вроде:

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

Вытащить мои волосы здесь... любые мысли?

Ответы

Ответ 1

Обычно вы можете просто передать массив требуемого типа в качестве параметра in-out, aka

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))

Ответ 2

расшифровка оболочки для @Nate Cook awesome answer, не может заставить версию 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
        }
    }
}