'withUnsafeBytes' является устаревшим предупреждением при передаче аргумента void * функции c в swift 5

У меня есть библиотека для быстрого анализа файла FIT с использованием внешней библиотеки C. Функция синтаксического анализа принимает в качестве аргумента void * data. Чтобы вызвать функцию, я преобразовывал данные с помощью data.withUnsafeBytes( { (ptr: UnsafePointer<UInt8>) in ...} для построения аргумента функции c, и она работала нормально.

После обновления Xcode до swift 5 я теперь получаю предупреждение об устаревании.

withUnsafeBytes устарел: вместо этого используйте withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R

Я не мог понять, как исправить код, чтобы удалить устаревшее предупреждение. Код работает нормально и без предупреждения в Swift 4

Я попытался изменить аргумент в закрытии, чтобы использовать UnsafeRawBufferPointer вместо UnsafePointer, но это привело к ошибке при вызове функции: Cannot convert 'UnsafeRawBufferPointer' to expected argument type 'UnsafeRawPointer?'

Это небольшой быстрый файл, показывающий проблему:

import Foundation

// Create sample data (Typically would be read from a file
let data = Data(repeating: 1, count: 10)

data.withUnsafeBytes( { (ptr : UnsafePointer<UInt8>) in
    // call the c function with the void* argument
    let value = readFITfile(ptr)
    print( value )
})

И пример функции c

unsigned readFITfile(const void * data){
    //Silly example to show it works, just returning the value of pointer as int
    //Typically would parse the data and return a structure
    return (unsigned)data;
}

Я сохранил небольшое репо с приведенным выше кодом здесь https://github.com/roznet/swift2c и полномасштабный проект с парсингом файла здесь https://github.com/roznet/fit-sdk-swift


person Brice    schedule 31.03.2019    source источник


Ответы (2)


Вы должны изменить аргумент закрытия на UnsafeRawBufferPointer, а затем взять его baseAdress (который является UnsafeRawPointer?, Swift-эквивалентом void * в C):

data.withUnsafeBytes( { (ptr : UnsafeRawBufferPointer) in
    let value = readFITfile(ptr.baseAddress)
    // ...
})

Компилятор Swift также может автоматически определять тип аргумента закрытия:

data.withUnsafeBytes( { ptr in
    let value = readFITfile(ptr.baseAddress)
    // ...
})

Дополнительные сведения об этой проблеме см. В разделе withUnsafeBytes Data API в форум Swift.

person Martin R    schedule 31.03.2019

Чтобы получить UnsafePointer сейчас, вам нужно сделать что-то вроде этого

data.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in
    if let ptrAddress = ptr.baseAddress, ptr.count > 0 {
        let pointer = ptrAddress.assumingMemoryBound(to: UInt8.self) // here you got UnsafePointer<UInt8>
        let value = readFITfile(ptr)
        print( value )
    } else {
        // Here you should provide some error handling if you want ofc
    }
}
person Anton Grigorev    schedule 31.03.2019
comment
Данная функция C принимает аргумент void *, нет необходимости преобразовывать UnsafeRawPointer в UnsafePointer<UInt8>. - person Martin R; 31.03.2019
comment
Кстати, ptr.baseAddress не может быть nil для непустого указателя буфера. - person Martin R; 31.03.2019