【iOS】UUIDの取得の最適化

[元ブログ - 【iOS】UUIDの取得の最適化 - 技術は熱いうちに打て！](http://blog.dalt.me/1168)

今回はiOSのUUIDの取得について書きます。

端末で一意なIDを取得したい、と思った時に使うこのUUID。
ちょっと調べるだけでいくつもやり方が出てきます。
一体どれが良いのか、調べてみたので書いてみます。

## 結論

一意性の高い順番で書いていきます。

・1位: [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString]
・2位: [[UIDevice currentDevice].identifierForVendor UUIDString]
・3位: [[NSProcessInfo processInfo] globallyUniqueString]
・4位: [[NSUUID UUID] UUIDString]
・4位: CoreFoundation(allocator: Default[ = nil ] )
・4位: CoreFoundation(allocator: SystemDefault)

となりました。

### 1位: [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString]

参考: <a href="https://developer.apple.com/library/ios/documentation/AdSupport/Reference/ASIdentifierManager_Ref/" target="_blank">ASIdentifierManager</a>

アプリを削除しようとも何回呼ぼうとも一意です。
ただし注意点もあります。

<a href="http://qiita.com/monry/items/b473e3db7e48f05be96b" target="_blank">【追記あり】ASIdentifierManager の advertisingIdentifier を使っているとリジェクトされる問題</a>
にもある通り、用途によってはリジェクトされるリスクもあるそうです。

注意:
・広告以外の用途に使ってはならない（アプリのサブミット時に広告以外に使っていないことを宣誓する必要がある）
・「何回呼ぼうとも一意」ではない。ユーザーが任意のタイミングでリセットすることができる（設定→プライバシー→広告→Advertising Identifierをリセット）
・advertisingTrackingEnabled == NO の場合、追跡型広告のために使用してはならない（取得はできる。追跡型広告以外の普通の広告のユニークブラウザ数の計測などに利用することは許容されるということだと思われる）

### 2位: [[UIDevice currentDevice].identifierForVendor UUIDString]

参考: <a href="https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIDevice_Class/" target="_blank">UIDevice</a>

こちらもアプリを削除しようとも、何回呼ぼうとも一意です。
そして、注目すべき点は<em>同一ベンダーで一意のIDを返す</em>点です。
同一ベンダーの判定はアプリのbundleIdのドメイン部分を見ている様です。

が、注意点もあります。

<em>同一ベンダーのアプリを全て削除すると変わる</em>

というものです。
調べてみましたが、変わる様子はなく。。。
しばらく時間を置く必要があるのでしょうか？

### 3位: [[NSProcessInfo processInfo] globallyUniqueString]

参考: <a href="https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Reference/Foundation/Classes/NSProcessInfo_Class/index.html" target="_blank">NSProcessInfo</a>

ここからは呼ばれる度に値が変わります。
ですが、プロセスが同じであれば一部同じ箇所もある事を加味し3位としました。
また、他のUUIDより桁数は多いです。

### 4位: [[NSUUID UUID] UUIDString]

参考: <a href="https://developer.apple.com/library/prerelease/ios/documentation/Foundation/Reference/NSUUID_Class/index.html" target="_blank">NSUUID</a>

こちらが一番オーソドックスな取得法のようですね。
ですが、呼び出しごとに変わるのでNSUserDefaultやファイルとして保存する必要がありそうです。

### 4位: CoreFoundation(allocator: Default[ = nil ] )

参考: <a href="https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFUUIDRef/" target="_blank">CFUUID Reference</a>

```objc:cf_uuid1
// CoreFoundation(allocator: Default[ = nil ] )
CFUUIDRef ref   = CFUUIDCreate(kCFAllocatorDefault);
NSString* uuid1 = (NSString*)CFUUIDCreateString(kCFAllocatorDefault, ref);
NSLog(@"uuid1: %@", uuid1);
CFRelease(ref);
```

### 4位: CoreFoundation(allocator: SystemDefault)

```objc:cf_uuid2
// CoreFoundation(allocator: SystemDefault)
CFUUIDRef ref2  = CFUUIDCreate(kCFAllocatorSystemDefault);
NSString* uuid2 = (NSString*)CFUUIDCreateString(kCFAllocatorSystemDefault, ref2);
NSLog(@"uuid2: %@", uuid2);
CFRelease(ref2);
```

## 実験結果
<pre>
初回起動時
uuid1: D3E65F07-E・・・AB212
uuid2: 0B23BD70-0・・・DE5D9
uuid3: 3BF2CF0F-B・・・DA725-401-0000003F4F91573A
uuid4: EC851F9A-C・・・AFEEE
uuid5: 9B40281C-A・・・D90D9
uuid6: 1C6AAEA0-6・・・83B81
</pre>

<pre>
同一起動で再呼び出し
uuid1: 5BADAF2F-1・・・8A68C
uuid2: 78562967-B・・・19F7A
uuid3: 51DE6D4C-4・・・5DD51-401-0000003F7341938D
uuid4: EC851F9A-C・・・AFEEE
uuid5: 9B40281C-A・・・D90D9
uuid6: 95E04F6C-C・・・2F4CE
</pre>

<pre>
再起動
uuid1: 1AC35B91-8・・・B1E32
uuid2: 8412AB1A-C・・・401C4
uuid3: C1890C58-1・・・DE72E-407-0000003FBD876CCE
uuid4: EC851F9A-C・・・AFEEE
uuid5: 9B40281C-A・・・D90D9
uuid6: 09E8CBD8-D・・・ED286
</pre>

<pre>
アプリ削除
uuid1: 0331D547-7・・・088C3
uuid2: 7BB80816-5・・・D67A0
uuid3: 4FC060A3-F・・・C2377-416-00000040268B24DC
uuid4: EC851F9A-C・・・AFEEE
uuid5: 9B40281C-A・・・D90D9
uuid6: 5823B616-7・・・E100B
</pre>

誰かのお役に立てば。