2

在更新到 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

4

2 回答 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、调试/发布、添加看似无关的代码......)会使您的应用程序崩溃。

而且更重要的一点是 UTF-8DatauuidString的字节序列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>
于 2016-10-07T14:26:14.550 回答
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 参数始终只保证在被调用函数返回之前有效,并且被调用函数必须在当前函数之前返回,所以这不会出错。

对于那些不知道的人,转换UUIDNSUUID( ... 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))
    }
}
于 2017-03-10T14:53:01.597 回答