Search code examples
swift3uuidunsafe-pointersnsuuid

Convert NSUUID to UnsafePointer<UInt8>


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


Solution

  • 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>