Swift Mutable Pointer переопределяется

Итак, у меня есть код для определения глубины на двух изображениях. Обнаружение глубины происходит в собственном коде C. Чтобы сделать вызов библиотеки C, у меня есть еще одна функция для построения массивов Int16, которые я передаю в качестве параметров.

Однако, когда я делаю вызовы функций непосредственно в параметрах вызова C, он перезаписывает первый вызов функции и дважды передает один и тот же параметр.

Вот что я имею в виду, это мой вызов библиотеки C:

let result = ImageProcessing.depthDetection(leftPhoto.cgImage!,
                                            right: rightPhoto.cgImage!,
                                            leftFace: getFaceDetails(image: leftPhoto, face: leftFace!).mutablePointer,
                                            rightFace: getFaceDetails(image: rightPhoto, face: rightFace!).mutablePointer))

Вызов получения сведений о лице выглядит следующим образом:

private func getFaceDetails(image: UIImage, face: VisionFace) -> [Int16] {
    var details = [Int16](repeating: 0, count: 10)
    // get image size
    details[0] = Int16(image.size.width)
    details[1] = Int16(image.size.height)

    // get face bounds
    details[2] = Int16(face.frame.origin.x)
    details[3] = Int16(face.frame.origin.y)
    details[4] = Int16(face.frame.origin.x + face.frame.width)
    details[5] = Int16(face.frame.origin.y + face.frame.height)

    // get eye locations
    details[6] = Int16(truncating: face.landmark(ofType: .leftEye)?.position.x ?? 0)
    details[7] = Int16(truncating: face.landmark(ofType: .leftEye)?.position.y ?? 0)
    details[8] = Int16(truncating: face.landmark(ofType: .rightEye)?.position.x ?? 0)
    details[9] = Int16(truncating: face.landmark(ofType: .rightEye)?.position.y ?? 0)

    print("Details: \(details)")

    return details
}

и я получаю изменяемый указатель с этим расширением:

extension Array where Element == Int16 {
    var mutablePointer: UnsafeMutablePointer<Int16> {
        get {
            return UnsafeMutablePointer<Int16>(mutating: self)
        }
    }
}

Итак, когда я запускаю приведенный выше вызов ImageProcessing.depthDetection, я вижу, что мои массивы leftFace и rightFace действительно разные и выглядят так:

Details: [3088, 2320, 1119, 431, 2230, 1542, 1493, 888, 1892, 882]
Details: [3088, 2320, 864, 446, 1975, 1556, 1207, 900, 1626, 890]

но когда я распечатываю их на C, они оба совпадают с массивом rightFace и выглядят так (я форматирую свои журналы C по-разному, но вы можете сказать, что и слева, и справа есть одинаковые данные):

0: Left (3088, 2320), Right (3088, 2320)
1: Left (864, 446), Right (864, 446)
2: Left (1975, 1556), Right (1975, 1556)
3: Left (1207, 900), Right (1207, 900)
4: Left (1626, 890), Right (1626, 890)

Так почему же первый вывод getFaceDetails перекрывается вторым?

Самое странное во всем этом то, что если я назначу результат getFaceDetails переменной, а затем передам эту переменную в качестве параметра, как я делаю здесь:

let lf = getFaceDetails(image: leftPhoto, face: leftFace!)
let rf = getFaceDetails(image: rightPhoto, face: rightFace!)

let result = ImageProcessing.depthDetection(leftPhoto.cgImage!,
                                            right: rightPhoto.cgImage!,
                                            leftFace: lf.mutablePointer,
                                            rightFace: rf.mutablePointer)

Потом вдруг все работает! Мои операторы печати в C показывают разные данные для левого и правого лица. Только когда я передаю вызовы функций в параметрах напрямую, у них неправильные данные.

Так что здесь происходит? Почему первый способ, которым я это делаю, не дает тех же результатов, что и последний?


person Quinn    schedule 04.03.2019    source источник
comment
Аналогичное поведение, вероятно, аналогичная причина: форумы .swift.org/t/   -  person jscs    schedule 04.03.2019
comment
Я думаю, что ваша функция mutablePointer в корне ошибочна. Он указывает на буфер массива, но не поддерживает его активность, поэтому, как только массив деинициализируется, указатель становится висящим.   -  person Alexander    schedule 04.03.2019
comment
Это поведение undefined — при передаче self в UnsafeMutablePointer<Int16>.init(mutating:) используется преобразование массива в указатель, которое создает временный указатель, действительный только на время вызова инициализатора. Любая попытка использовать результирующий указатель является поведением undefined. (Мне действительно нужно вернуться к этому PR, когда у меня будет время)   -  person Hamish    schedule 05.03.2019


Ответы (1)


Как указывалось в нескольких комментариях, это поведение undefined:

extension Array where Element == Int16 {
    var mutablePointer: UnsafeMutablePointer<Int16> {
        get {
            return UnsafeMutablePointer<Int16>(mutating: self)
        }
    }
}

Как только UnsafeMutablePointer.init(mutating:) возвращается, предоставляемый им указатель становится бессмысленным. Вы имеете в виду что-то в этом роде:

let result = lf.withUnsafeMutableBytes { lfBytes in
    rf.withUnsafeMutableBytes { rfBytes in
        return ImageProcessing.depthDetection(leftPhoto.cgImage!,
                                              right: rightPhoto.cgImage!,
                                              leftFace: lfBytes,
                                              rightFace: rhBytes)
    }
}

В качестве альтернативы вы можете сделать что-то в этом роде:

let result = ImageProcessing.depthDetection(leftPhoto.cgImage!,
                                            right: rightPhoto.cgImage!,
                                            leftFace: &lf,
                                            rightFace: &rf)

Но ключевым моментом является то, что возвращать UnsafeMutablePointer бессмысленно, если у вас нет какого-то способа гарантировать время жизни конкретной вещи, на которую вы взяли указатель, что почти всегда верно, за исключением блока withUnsafe....

person Rob Napier    schedule 04.03.2019