将NSUUID转换为UnsafePointer

问题描述 投票:2回答:2

在对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

swift3 uuid unsafe-pointers nsuuid
2个回答
3
投票

一个正确的方法:

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>

3
投票

你觉得太复杂了:

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))
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.