将 NSUUID 转换为 UnsafePointer<UInt8>
Convert NSUUID to UnsafePointer<UInt8>
更新 Swift 3 后,getUUIDBytes
和 getBytes
似乎在 UUID
对象上都不可用。
let uuid = UIDevice.current.identifierForVendor
let mutableUUIDData = NSMutableData(length:16)
uuid.getBytes(UnsafeMutablePointer(mutableUUIDData!.mutableBytes))
// ^^^ compiler error, value of type UUID? has no member getBytes
即使在文档中将 getBytes
列为 UUID 上的方法时,我也会收到此错误:https://developer.apple.com/reference/foundation/nsuuid/1411420-getbytes
一个正确的方法:
let uuid = UIDevice.current.identifierForVendor!
var rawUuid = uuid.uuid
withUnsafePointer(to: &rawUuid) {rawUuidPtr in //<- `rawUuidPtr` is of type `UnsafePointer<uuid_t>`.
rawUuidPtr.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<uuid_t>.size) {bytes in
//Use `bytes` only in this closure. (Do NEVER export `bytes` out of the closure.)
print(bytes[0],bytes[1])
//...
}
}
另一个正确的方法:
withUnsafePointer(to: &rawUuid) {rawUuidPtr in //<- `rawUuidPtr` is of type `UnsafePointer<uuid_t>`.
let bytes = UnsafeRawPointer(rawUuidPtr).assumingMemoryBound(to: UInt8.self)
//Use `bytes` only in this closure. (Do NEVER export `bytes` out of the closure.)
print(bytes[0],bytes[1])
//...
}
正如 Rob 已经评论的那样,完全不能保证导出传递给 withUnsafeBytes
的闭包参数的指针。上下文的轻微变化(32-bit/64-bit、x86/ARM、Debug/Release、添加看似无关的代码...)会使您的应用崩溃。
还有一个更重要的是uuidString
的UTF-8Data
和NSUUID.getBytes
的字节序列是完全不同的:
let nsUuid = uuid as NSUUID //<-Using the same `UUID`
let mutableUUIDData = NSMutableData(length:16)!
nsUuid.getBytes(mutableUUIDData.mutableBytes.assumingMemoryBound(to: UInt8.self))
print(mutableUUIDData) //-><1682ed24 09224178 a279b44b 5a4944f4>
let uuidData = uuid.uuidString.data(using: .utf8)!
print(uuidData as NSData) //-><31363832 45443234 2d303932 322d3431 37382d41 3237392d 42343442 35413439 34344634>
你想的太复杂了:
func getUUID ( ) -> Data {
let uuid = NSUUID()
var bytes = [UInt8](repeating: 0, count: 16)
uuid.getBytes(&bytes)
return Data(bytes: bytes)
}
为什么这样行得通?
考虑你有:
func printInt(atAddress p: UnsafeMutablePointer<Int>) {
print(p.pointee)
}
那么你实际上可以这样做:
var value: Int = 23
printInt(atAddress: &value)
// Prints "23"
但您也可以这样做:
var numbers = [5, 10, 15, 20]
printInt(atAddress: &numbers)
// Prints "5"
它是 "implicit bridging" 的一种形式。引用自Swiftdoc.org:
A mutable pointer to the elements of an array is implicitly created
when you pass the array using inout syntax.
此隐式桥接仅保证在当前函数 return 之前有效的指针。这样的指针绝不能 "escape" 当前函数上下文,但将它们用作 inout 参数始终是安全的,因为 inout 参数始终只保证在被调用函数 return 之前有效并且被调用函数必须return 在当前版本之前,所以这不会出错。
对于那些不知道的人,将 UUID
转换为 NSUUID
(... as NSUUID
) 并反过来 (... as UUID
) 保证总是成功.但是如果你坚持使用UUID
,最简单的方法是:
private
func getUUID ( ) -> Data {
var uuid = UUID().uuid
return withUnsafePointer(to: &uuid) {
return Data(bytes: [=14=], count: MemoryLayout.size(ofValue: uuid))
}
}
更新 Swift 3 后,getUUIDBytes
和 getBytes
似乎在 UUID
对象上都不可用。
let uuid = UIDevice.current.identifierForVendor
let mutableUUIDData = NSMutableData(length:16)
uuid.getBytes(UnsafeMutablePointer(mutableUUIDData!.mutableBytes))
// ^^^ compiler error, value of type UUID? has no member getBytes
即使在文档中将 getBytes
列为 UUID 上的方法时,我也会收到此错误:https://developer.apple.com/reference/foundation/nsuuid/1411420-getbytes
一个正确的方法:
let uuid = UIDevice.current.identifierForVendor!
var rawUuid = uuid.uuid
withUnsafePointer(to: &rawUuid) {rawUuidPtr in //<- `rawUuidPtr` is of type `UnsafePointer<uuid_t>`.
rawUuidPtr.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<uuid_t>.size) {bytes in
//Use `bytes` only in this closure. (Do NEVER export `bytes` out of the closure.)
print(bytes[0],bytes[1])
//...
}
}
另一个正确的方法:
withUnsafePointer(to: &rawUuid) {rawUuidPtr in //<- `rawUuidPtr` is of type `UnsafePointer<uuid_t>`.
let bytes = UnsafeRawPointer(rawUuidPtr).assumingMemoryBound(to: UInt8.self)
//Use `bytes` only in this closure. (Do NEVER export `bytes` out of the closure.)
print(bytes[0],bytes[1])
//...
}
正如 Rob 已经评论的那样,完全不能保证导出传递给 withUnsafeBytes
的闭包参数的指针。上下文的轻微变化(32-bit/64-bit、x86/ARM、Debug/Release、添加看似无关的代码...)会使您的应用崩溃。
还有一个更重要的是uuidString
的UTF-8Data
和NSUUID.getBytes
的字节序列是完全不同的:
let nsUuid = uuid as NSUUID //<-Using the same `UUID`
let mutableUUIDData = NSMutableData(length:16)!
nsUuid.getBytes(mutableUUIDData.mutableBytes.assumingMemoryBound(to: UInt8.self))
print(mutableUUIDData) //-><1682ed24 09224178 a279b44b 5a4944f4>
let uuidData = uuid.uuidString.data(using: .utf8)!
print(uuidData as NSData) //-><31363832 45443234 2d303932 322d3431 37382d41 3237392d 42343442 35413439 34344634>
你想的太复杂了:
func getUUID ( ) -> Data {
let uuid = NSUUID()
var bytes = [UInt8](repeating: 0, count: 16)
uuid.getBytes(&bytes)
return Data(bytes: bytes)
}
为什么这样行得通?
考虑你有:
func printInt(atAddress p: UnsafeMutablePointer<Int>) {
print(p.pointee)
}
那么你实际上可以这样做:
var value: Int = 23
printInt(atAddress: &value)
// Prints "23"
但您也可以这样做:
var numbers = [5, 10, 15, 20]
printInt(atAddress: &numbers)
// Prints "5"
它是 "implicit bridging" 的一种形式。引用自Swiftdoc.org:
A mutable pointer to the elements of an array is implicitly created when you pass the array using inout syntax.
此隐式桥接仅保证在当前函数 return 之前有效的指针。这样的指针绝不能 "escape" 当前函数上下文,但将它们用作 inout 参数始终是安全的,因为 inout 参数始终只保证在被调用函数 return 之前有效并且被调用函数必须return 在当前版本之前,所以这不会出错。
对于那些不知道的人,将 UUID
转换为 NSUUID
(... as NSUUID
) 并反过来 (... as UUID
) 保证总是成功.但是如果你坚持使用UUID
,最简单的方法是:
private
func getUUID ( ) -> Data {
var uuid = UUID().uuid
return withUnsafePointer(to: &uuid) {
return Data(bytes: [=14=], count: MemoryLayout.size(ofValue: uuid))
}
}