В Swift 3, Как я могу получить UnsafeRawPointer из данных?
согласно документации данных в Swift 3, есть инициализатор, который я могу использовать для создания данных из UnsafeRawPointer. На самом деле мне нужно обратное. У меня есть данные, и я хочу создать UnsafeRawPointer, который указывает на байты данных. Вот что я сейчас делаю:--2-->
1. let data = <from some where>
2. let unsafePointer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
3. unsafePointer.initialize(to: 0, count: data.count) // is this necessary?
4. data.copyBytes(to: unsafePointer, count: data.count)
5. let unsafeRawPointer = unsafePointer.deinitialize() // this is of the type UnsafeMutalbleRawPointer, and I can use it where UnsafeRawPointer is needed.
Я проверил, что этот код работает в Xcode Playground. Код даже работает без строки номер 3. Я не уверен, какая разница с линией или без нее. В любом случае, мой вопрос в том, правильно ли я поступаю для того, чего хочу? Существует ли более простой способ сделать это?
2 ответов
withUnsafeBytes()
дает вам (типизированный) указатель на байты,
это можно преобразовать в необработанный указатель:
let data = <Data from somewhere>
data.withUnsafeBytes { (u8Ptr: UnsafePointer<UInt8>) in
let rawPtr = UnsafeRawPointer(u8Ptr)
// ... use `rawPtr` ...
}
указатель действителен только в течение срока вызова закрытие.
кроме того, вы можете перейти на NSData
и получить доступ к необработанным байтам:
let nsData = data as NSData
let rawPtr = nsData.bytes
теперь указатель действителен в той же области, где nsData
действителен.
Регистрация последняя ссылка.
мы не можем найти метод или свойство, которое получает UnsafeRawPointer
С Data
.
так, для альтернативы: func withUnsafeBytes ((UnsafePointer) -> ResultType)
вы можете писать что-то вроде этого:
let data: Data = <initialize it as you like>
data.withUnsafeBytes {(uint8Ptr: UnsafePointer<UInt8>) in
let rawPtr = UnsafeRawPointer(uint8Ptr)
//`rawPtr` (and `uint8Ptr`) is guaranteed to be valid in this closure
//...
//You have no need manage `rawPtr`.
}
(О, это то же самое, что и первая половина ответа Мартина Р.)
но если вы хотите сохранить ваш UnsafeRawPointer
действует в течение более длительного периода чем в закрытии, вам нужно сделать копию содержимого Data
:
например:
let uint8Ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
uint8Ptr.initialize(from: data) //<-copying the data
//You need to keep `uint8Ptr` and `data.count` for future management
let uint8PtrCount = data.count
//You can convert it to `UnsafeRawPointer`
let rawPtr = UnsafeRawPointer(uint8Ptr)
//Use `rawPtr` while `uint8Ptr` is valid
//...
//Deinitialize and deallocate the region
uint8Ptr.deinitialize(count: uint8PtrCount)
uint8Ptr.deallocate(capacity: uint8PtrCount)
(вы можете сделать UnsafeMutableRawPointer
как возвращаемое значение deinitialize(count:)
, но регион в неинициализированные состояние, поэтому вы не должны получить доступ к региону.)