2

Following the update to Swift 3, it appears both getUUIDBytes and getBytes are not available on the UUID object.

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

I get this error even when getBytes is listed as a method on UUID in the documentation: https://developer.apple.com/reference/foundation/nsuuid/1411420-getbytes

ray
  • 1,966
  • 4
  • 24
  • 39

2 Answers2

3

One right way:

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])
        //...
    }
}

Another right way:

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])
    //...
}

As already commented by Rob, exporting the pointer passed to the closure argument of withUnsafeBytes is completely NOT guaranteed. A slight change of the context (32-bit/64-bit, x86/ARM, Debug/Release, adding seemingly unrelated code...) would make your app a crasher.

And one more important thing is that UTF-8 Data of the uuidString and the byte sequence of NSUUID.getBytes are completely different:

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>
OOPer
  • 47,149
  • 6
  • 107
  • 142
  • I'd like to get your input then, I have 3 `Data` vars whose `bytes` I need to pass to `SHA1_Update` in sequence. Is the recommend flow really to have 3 nested blocks of `withUnsafeBytes`? – ray Oct 07 '16 at 15:08
  • @ray, seems that is the right way when working with `Data` in Swift 3. Or else you can work with `Unsafe[Mutable]Pointer`. Someone (Apple's staff in the Apple's dev forum) has suggested to write a more Swifty wrapper in C/Objective-C. – OOPer Oct 07 '16 at 15:16
3

You are thinking too complicated:

func getUUID ( ) -> Data {
    let uuid = NSUUID()
    var bytes = [UInt8](repeating: 0, count: 16)
    uuid.getBytes(&bytes)
    return Data(bytes: bytes)
}

Why does that work?

Consider you have:

func printInt(atAddress p: UnsafeMutablePointer<Int>) {
    print(p.pointee)
}

then you can in fact do this:

var value: Int = 23
printInt(atAddress: &value)
// Prints "23"

but you can also do this:

var numbers = [5, 10, 15, 20]
printInt(atAddress: &numbers)
// Prints "5"

It's a form of "implicit bridging". To quote from Swiftdoc.org:

A mutable pointer to the elements of an array is implicitly created when you pass the array using inout syntax.

This implicit bridging only guarantees valid pointers until the current function returns. Such pointers must never "escape" the current function context, but using them as an inout argument is always safe, as inout arguments were always only guarantee to be valid until the called function returns and the called function must return prior to the current one, so this cannot go wrong.

And for those that don't know, casting UUID to NSUUID (... as NSUUID) and the other way round (... as UUID) is guaranteed to always succeed. But if you insist on using UUID, the easiest way is:

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