I have the following code written in Objective C that I am trying to get working in Swift 3. Some of the functions equivalents do not appear to be available in Swift 3. Here is the code is the code in Objective C
NSUUID *vendorIdentifier = [[UIDevice currentDevice] identifierForVendor];
uuid_t uuid;
[vendorIdentifier getUUIDBytes:uuid];
NSData *vendorData = [NSData dataWithBytes:uuid length:16];
and my current effort in Swift 3 which compiles and runs but is not giving the correct answer.
let uuid = UIDevice.current.identifierForVendor?.uuidString
let uuidData = uuid?.data(using: .utf8)
let uuidBytes = uuidData?.withUnsafeBytes { UnsafePointer<UInt8>($0) }
let vendorData : NSData = NSData.init(bytes: uuidBytes, length: 16)
let hashData = NSMutableData()
hashData.append(vendorData as Data)
The uuid
property of UUID
is a C array with is imported to Swift
as a tuple. Using the fact that Swift preserves the memory layout
of imported C structures, you can pass a pointer to the tuple
to the Data(bytes:, count:)
constructor:
if let vendorIdentifier = UIDevice.current.identifierForVendor {
var uuid = vendorIdentifier.uuid
let data = withUnsafePointer(to: &uuid) {
Data(bytes: $0, count: MemoryLayout.size(ofValue: uuid))
}
// ...
}
As of Swift 4.2 (Xcode 10) your don't need to make a mutable
copy first:
if let vendorIdentifier = UIDevice.current.identifierForVendor {
let data = withUnsafePointer(to: vendorIdentifier.uuid) {
Data(bytes: $0, count: MemoryLayout.size(ofValue: vendorIdentifier.uuid))
}
// ...
}
Here's one possible way. Note that identifierForVendor
returns UUID
in Swift 3. UUID
has a uuid
property which gives you a uuid_t
. uuid_t
is a tuple of 16 UInt8
values.
So the trick is converting the tuple of bytes into an array of bytes. Then it's trivial to create the Data
from the array.
if let vendorIdentifier = UIDevice.current.identifierForVendor {
let uuid = vendorIdentifier.uuid // gives a uuid_t
let uuidBytes = Mirror(reflecting: uuid).children.map({$0.1 as! UInt8}) // converts the tuple into an array
let vendorData = Data(bytes: uuidBytes)
}
If anyone knows a better way to convert a tuple of UInt8
into an array of UInt8
, please speak up.
This extension I made seems to work great without using reflection, nor pointers. It depends on the fact that UUID in Swift is represented as a tuple of 16 UInt8
s which can simply be unwrapped like so:
extension UUID{
public func asUInt8Array() -> [UInt8]{
let (u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15,u16) = self.uuid
return [u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15,u16]
}
public func asData() -> Data{
return Data(self.asUInt8Array())
}
}
To translate a UUID
to Data
in Swift 4.2, I used this:
let uuid = UUID()
withUnsafeBytes(of: uuid.uuid, { Data($0) })
Swift 4.2 Extension
public extension UUID {
var data: Data {
return withUnsafeBytes(of: self.uuid, { Data($0) })
}
}