I'm calling a C function in a library which requires pointers to uint8_t
buffers. I'm attempting to refer to UInt8 arrays in Swift as follows (to later pass to the C function):
import Foundation
struct CStruct {
let val: UnsafeMutablePointer<UInt8>
let count: UInt32
}
var structs = [CStruct]()
var datas = [[UInt8]]()
for _ in 0..<10 {
// In the real application, Data contains data rather than being zero length
let d = Data()
var data = [UInt8](d)
// I don't want the `data` buffers to be deallocated, so I store them in an array.
datas.append(data)
structs.append(CStruct(val: &data, count: UInt32(data.count)))
}
print("Structs: \(structs)")
// pass the structs to a C function which processes them
This gives the warning
Inout expression creates a temporary pointer, but argument 'val' should be a pointer that outlives the call to 'init(val:count:)'
I can't use data.withUnsafeMutableBufferPointer
as the pointer it provides would be out of scope outside the closure. I can't use Unmanaged
as that only operates on classes, and Array
is a struct. I'm also not sure that adding the data
array to an array in the parent scope will extend its lifetime (as it is a struct). What is the correct way to achieve this?
edit:
My solution, based on @bscothern's answer:
import Foundation
struct CStruct {
let val: UnsafeMutablePointer<UInt8>
let count: UInt32
}
var structs = [CStruct]()
var dataStorage: [UnsafeMutablePointer<UInt8>] = []
for _ in 0..<10 {
// In the real application, Data contains data rather than being zero length
let d = Data()
let ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: d.count)
d.withUnsafeBytes { (buff) -> Void in
ptr.initialize(from: buff.bindMemory(to: UInt8.self).baseAddress!, count: d.count)
}
dataStorage.append(ptr)
structs.append(CStruct(val: ptr, count: UInt32(d.count)))
}
defer {
for ptr in dataStorage {
ptr.deallocate()
}
dataStorage = []
}
print("Structs: \(structs)")
// pass the structs to a C function which processes them
Perhaps there is a better way to copy from Data
?