UUIDの取得、保存方法


UUIDが既にある場合は存在するUUIDを返します。
ない場合は新たに生成したUUIDを返します。

DataStoreではUserDefaultにuuidを保存しています。
ここは実装に合わせて変更して大丈夫です。

キーチェーンはiTunesにバックアップされない為、機種変更でデータが消えてしまうのでUserDefaultに保存しています。

キーチェーンに保存しなければアプリを消した時にUserDefaultのデータは消えてしまうのでUserDefaultとキーチェーンの両方に値を保存しています。

```objectivec:

static NSString * const UUID_Key = @"hoge";

+ (NSString*)getUUID {
    NSString *uuidString = nil;
    
    //まずはUserDefaultにUUIDがあるか調べてみる
    DataStore* dataStore = [DataStore instance];
    if (dataStore.baseData.uuid) {
        uuidString = dataStore.baseData.uuid;
        NSLog(@"UserDefaultにUUIDがあった場合 %@", uuidString);
    }
    //ない場合はキーチェーンから探す
    else {
        NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
                               (__bridge id)kSecClassGenericPassword,   (__bridge id)kSecClass,
                               UUID_Key,                  (__bridge id)kSecAttrGeneric,
                               UUID_Key,                  (__bridge id)kSecAttrAccount,
                               [[NSBundle mainBundle] bundleIdentifier],(__bridge id)kSecAttrService,
                               (__bridge id)kSecMatchLimitOne,          (__bridge id)kSecMatchLimit,
                               (__bridge id)kCFBooleanTrue,             (__bridge id)kSecReturnAttributes,
                               nil];
        CFTypeRef attributesRef = NULL;
        OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)query, &attributesRef);
        if (result == noErr) {
            NSDictionary *attributes = (__bridge_transfer NSDictionary *)attributesRef;
            NSMutableDictionary *valueQuery = [NSMutableDictionary dictionaryWithDictionary:attributes];
            
            [valueQuery setObject:(__bridge id)kSecClassGenericPassword  forKey:(__bridge id)kSecClass];
            [valueQuery setObject:(__bridge id)kCFBooleanTrue            forKey:(__bridge id)kSecReturnData];
            
            CFTypeRef passwordDataRef = NULL;
            OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)valueQuery, &passwordDataRef);
            if (result == noErr) {
                NSData *passwordData = (__bridge_transfer NSData *)passwordDataRef;
                // Assume the stored data is a UTF-8 string.
                uuidString = [[NSString alloc] initWithBytes:[passwordData bytes]
                                                      length:[passwordData length]
                                                    encoding:NSUTF8StringEncoding];
            }
        }
        NSLog(@"UserDefaultにUUIDはない場合 %@", uuidString);
    }
    
    if (uuidString == nil) {

        // Generate the new UIID
        CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
        uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
        CFRelease(uuidRef);
        
        //以下はuuidが00000000-0000-0000-0000-000000000000になってしまう可能性があるので使わない
        //id identifier = [[UIDevice currentDevice] performSelector:@selector(identifierForVendor)];
        //uuidString = [identifier performSelector:@selector(UUIDString)];
        
        // UIID must be persistent even if the application is removed from devices
        // Use keychain as a storage
        NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                      (__bridge id)kSecClassGenericPassword,    (__bridge id)kSecClass,
                                      UUID_Key,                   (__bridge id)kSecAttrGeneric,
                                      UUID_Key,                   (__bridge id)kSecAttrAccount,
                                      [[NSBundle mainBundle] bundleIdentifier], (__bridge id)kSecAttrService,
                                      @"",                                      (__bridge id)kSecAttrLabel,
                                      @"",                                      (__bridge id)kSecAttrDescription,
                                      nil];
        
        if ([[[UIDevice currentDevice] systemVersion] floatValue] < 4) {
            // kSecAttrAccessible is iOS 4 or later only
            // Current device is running on iOS 3.X, do nothing here
        } else {
            // Set kSecAttrAccessibleAfterFirstUnlock so that background applications are able to access this key.
            // Keys defined as kSecAttrAccessibleAfterFirstUnlock will be migrated to the new devices/installations via encrypted backups.
            // If you want different UIID per device, use kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly instead.
            // Keep in mind that keys defined as kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly will be removed after restoring from a backup.
            [query setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlock forKey:(__bridge id)kSecAttrAccessible];
        }
        [query setObject:[uuidString dataUsingEncoding:NSUTF8StringEncoding] forKey:(__bridge id)kSecValueData];
        
        OSStatus result = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
        if (result != noErr) {
            NSLog(@"[ERROR] Couldn't add the Keychain Item. result = %ld query = %@", result, query);
            return nil;
        }
    }
    
    //UUIDをUserDefaultに保存する
    dataStore.baseData.uuid = uuidString;
    [dataStore saveDatas];
    
    return uuidString;
}
```