Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'withUnsafeBytes' is deprecated warning when passing void* argument to c function in swift 5

I have a library parsing FIT file in swift using an externally provided c library. The parsing function takes as argument a void * data. To call the function, I was converting the data using data.withUnsafeBytes( { (ptr: UnsafePointer<UInt8>) in ...} to build the argument to the c function and it was working fine.

After the upgrade of Xcode to swift 5, I now get a deprecated warning

'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R instead

I couldn't work out how to fix the code to remove the deprecated warning. The code has been working fine and without warning in swift 4

I tried to change the argument in the closure to take UnsafeRawBufferPointer instead of the UnsafePointer but this resulted in an error in calling the function: Cannot convert 'UnsafeRawBufferPointer' to expected argument type 'UnsafeRawPointer?'

This is a small swift file to show the problem:

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

And an example c function

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;
}

I saved a small repo with the above code here https://github.com/roznet/swift2c and the full scale project with the parsing of the file is here https://github.com/roznet/fit-sdk-swift

like image 721
Brice Avatar asked Mar 31 '19 10:03

Brice


2 Answers

You have to change the closure argument to UnsafeRawBufferPointer and then take its baseAdress (which is a UnsafeRawPointer?, the Swift equivalent of void * in C):

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

The Swift compiler can also infer the closure argument type automatically:

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

For more information about this problem, see withUnsafeBytes Data API confusion in the Swift forum.

like image 153
Martin R Avatar answered Nov 05 '22 04:11

Martin R


To get UnsafePointer now you should do something like that

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
    }
}
like image 3
Anton Grigorev Avatar answered Nov 05 '22 03:11

Anton Grigorev