У меня есть библиотека, анализирующая файл 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.
Вы должны изменить аргумент закрытия на 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.
Чтобы получить 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
}
}
Кстати, ptr.baseAddress
не можем будет nil
для непустого указателя буфера.
Данная функция C принимает аргумент
void *
, нет необходимости преобразовыватьUnsafeRawPointer
вUnsafePointer<UInt8>
.