Some people want to know more about the different options available, and if so, take a look at the answer from @ NSQuamber.java. If you want to know how to use NSUUID and sync with iCloud, keep reading. This post turned out to be longer than I originally wanted, but I hope it makes it clear who will take these steps!
Using NSUUID
I use the NSUUID class to create the UUID:
NSUUID *uuid = [NSUUID UUID];
Then, to create a string, you need to call the UUIDString method:
NSString *uuidString = [uuid UUIDString];
or do it in one line:
NSString *uuidString = [[NSUUID UUID] UUIDString];
IMHO, this is a lot easier than trying to use CFUUIDCreate and have a method that you must support.
EDIT: I am now using UICKeyChainStore
To set the UUID using UICKeyChainStore:
UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.sample.MyApp"]; keychain[@"com.sample.MyApp.user"] = userID;
To get it:
UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.sample.MyApp"]; NSString *userID = keychain[@"com.sample.MyApp.user"];
Then I saved this UUID in the keychain using SSKeyChain
To set the UUID using SSKeyChain:
[SSKeychain setPassword:userID forService:@"com.sample.MyApp.user" account:@"com.sample.MyApp"];
To get it:
NSString *userID = [SSKeychain passwordForService:@"com.sample.MyApp.user" account:@"com.sample.MyApp"];
When you set the UUID in the keychain, it will be saved even if the user completely uninstalls the application and then installs it again.
Sync with iCloud
Therefore, it is useful to make sure that all user devices use the same UUID. This is done to ensure data synchronization on all devices, and not with each device that considers it a unique user.
In the comments to my answer there were several questions about how synchronization will work, so now that I have everything worked out, I will tell you more.
Configure iCloud / NSUbiquitousKeyValueStore Using
- Click on your project at the top of Project Navigator in Xcode.
- Choose features.
- Enable iCloud.
Now it should look something like this: 
Using NSUbiquitousKeyValueStore
Using iCloud is pretty simple. To write:
Count:
Before you can write NSUbiquitousKeyValueStore documentation , you must first read iCloud. To force read, call the following method:
[[NSUbiquitousKeyValueStore defaultStore] synchronize];
To get your application notified of changes in iCloud, add the following notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(iCloudStoreDidChange:) name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification object:[NSUbiquitousKeyValueStore defaultStore]];
Create UUIDs with iCloud
Combining NSUUID, SSKeychain and NSUbiquityKeyValueStore, here is my method for generating the user ID:
- (NSUUID *)createUserID { NSString *userKey = @"com.sample.MyApp.user"; NSString *KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp"; NSString *userID = [SSKeychain passwordForService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER]; if (userID) { return [[NSUUID UUID] initWithUUIDString:userID]; }
How to keep your user ID in sync
Since writing to iCloud first requires loading any data into iCloud, I place the synchronization call at the beginning of the (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions . I also added registration posting there. This allows me to detect any changes from iCloud and process them accordingly.
Here is an example:
NSString *const USER_KEY = @"com.sample.MyApp.user"; NSString *const KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp"; - (void)iCloudStoreDidChange:(NSNotification *)notification { NSDictionary *userInfo = notification.userInfo; NSNumber *changeReason = userInfo[NSUbiquitousKeyValueStoreChangeReasonKey]; NSArray *keysChanged = userInfo[NSUbiquitousKeyValueStoreChangedKeysKey]; if (changeReason) { switch ([changeReason intValue]) { default: case NSUbiquitousKeyValueStoreServerChange: case NSUbiquitousKeyValueStoreInitialSyncChange: // check changed keys for (NSString *keyChanged in keysChanged) { NSString *iCloudID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:keyChanged]; if (![keyChanged isEqualToString:USER_KEY]) { NSLog(@"Unknown key changed [%@:%@]", keyChanged, iCloudID); continue; } // get the local key NSString *localID = [SSKeychain passwordForService:keyChanged account:KEYCHAIN_ACCOUNT_IDENTIFIER]; if (!iCloudID) { // no value from iCloud continue; } // local ID not created yet if (!localID) { // save the iCloud value locally [SSKeychain setPassword:iCloudID forService:keyChanged account:KEYCHAIN_ACCOUNT_IDENTIFIER]; continue; // continue because there is no user information on the server, so no migration } if ([iCloudID isEqualToString:localID]) { // IDs match, so continue continue; } [self handleMigration:keyChanged from:localID to:iCloudID]; } break; case NSUbiquitousKeyValueStoreAccountChange: // need to delete all data and download new data from server break; } } }
When the application starts or when it returns to the foreground, I force synchronization with iCloud and check the integrity of the UUID.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [self configureSecKeyWrapper]; // synchronize data from iCloud first. If the User ID already exists, then we can initialize with it [[NSUbiquitousKeyValueStore defaultStore] synchronize]; [self checkUseriCloudSync]; } - (void)applicationWillEnterForeground:(UIApplication *)application { // synchronize changes from iCloud [[NSUbiquitousKeyValueStore defaultStore] synchronize]; [self checkUseriCloudSync]; } - (BOOL)checkUseriCloudSync { NSString *userKey = @"com.sample.MyApp.user"; NSString *KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp"; NSString *localID = [SSKeychain passwordForService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER]; NSString *iCloudID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey]; if (!iCloudID) { // iCloud does not have the key saved, so we write the key to iCloud [[NSUbiquitousKeyValueStore defaultStore] setString:localID forKey:userKey]; return YES; } if (!localID || [iCloudID isEqualToString:localID]) { return YES; } // both IDs exist, so we keep the one from iCloud since the functionality requires synchronization // before setting, so that means that it was the earliest one [self handleMigration:userKey from:localID to:iCloudID]; return NO; }
If the first UUID came first
In my case of using my UserID, I suggested that the value in iCloud is what you need to save, as this will be the first UUID to be clicked on iCloud, regardless of which device generated the UUID first. Most of you are likely to follow the same path, since you won’t care which UUID it allows, as long as it allows one. For those of you who really care about what was first, I suggest you keep both the UUID and timestamp ( [[NSDate date] timeIntervalSince1970] ) so you can check which one is older: