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

あなたはあまりにも複雑に考えています:

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 UUIDUUID

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 に答える
3

1つの正しい方法:

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、デバッグ/リリース、一見無関係なコードを追加するなど)、アプリがクラッシュする可能性があります。

もう 1 つ重要なことは、 の 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 に答える