将NSUUID转换为UnsafePointer

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将NSUUID转换为UnsafePointer相关的知识,希望对你有一定的参考价值。

在对Swift 3进行更新后,getUUIDBytes对象上无法显示getBytesUUID

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位/ 64位,x86 / ARM,调试/发布,添加看似无关的代码......)将使您的应用程序变得更糟糕。

还有一个重要的事情是Data的UTF-8 uuidStringNSUUID.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"

这是“隐性桥接”的一种形式。引用Swiftdoc.org

使用inout语法传递数组时,将隐式创建指向数组元素的可变指针。

这种隐式桥接仅保证有效指针,直到当前函数返回。这样的指针绝不能“逃避”当前的函数上下文,但是使用它们作为inout参数总是安全的,因为inout参数始终只保证在被调用的函数返回并且被调用的函数必须在当前函数之前返回时才有效,所以这不会出错。

而对于那些不知道的人,将UUID投射到NSUUID... as NSUUID)和反过来(... as UUID)保证总是成功。但如果你坚持使用UUID,最简单的方法是:

private
func getUUID ( ) -> Data {
    var uuid = UUID().uuid
    return withUnsafePointer(to: &uuid) {
        return Data(bytes: $0, count: MemoryLayout.size(ofValue: uuid))
    }
}

以上是关于将NSUUID转换为UnsafePointer的主要内容,如果未能解决你的问题,请参考以下文章

无法将“UnsafePointer<Double>”类型的值转换为预期的参数类型“UnsafePointer<_>”

将 Int 转换为 UnsafePointer<UInt8>

在 Swift 中使用 C 字符串,或者:如何将 UnsafePointer<CChar> 转换为 CString

UnsafePointer 不再适用于 swift 3

如何转换 UnsafePointer<UnsafeMutablePointer<Float>>?到 UnsafeMutablePointer<UnsafeMutableP

写入 UnsafePointer<DSPSplitComplex> 的值