2016-10-07 6 views
2

После обновления до Swift 3 появляется getUUIDBytes и getBytes не доступны на объекте UUID.Преобразование NSUUID в UnsafePointer <UInt8>

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

ответ

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, Debug/Release, добавление, по-видимому, несвязанного кода ...) сделает ваше приложение крошечным.

И еще одна важная вещь, что UTF-8 Data из uuidString и последовательность байт 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> 
+0

Я хотел бы получить свой вклад тогда, у меня есть 3 'Data' вары, чей' bytes' мне нужно перейти к 'SHA1_Update' в последовательности ,Действительно ли рекомендуемый поток имеет 3 вложенных блока 'withUnsafeBytes'? – ray

+0

@ray, кажется, что это правильный путь при работе с 'Data' в Swift 3. Или вы можете работать с' Unsafe [Mutable] Pointer'. Кто-то (штат Apple в форуме разработчиков Apple) предложил написать более Swifty-обертку в C/Objective-C. – OOPer

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)) 
    } 
} 
+0

Очень просто. И это работает! – davidgyoung