Picture of Brian Love wearing black against a dark wall in Portland, OR.

Brian Love

Uniquely identify your iOS app users

In iOS 5 Apple deprecated the [UIDevice uniqueIdentier], which returned the UDID (Unique Device Identifier).

This 40 character hex is a unique device ID that is assigned by Apple to each device. This was previously a great way to identify each unique device, or user of your application, and is often used when an app persists data to a remote server. So, what is a developer to do these days?

The most common approach to this problem is to create your own unique identifier and store it in the NSUserDefaults preferences file. I previously wrote about NSUserDefaults and the ability to register default values for user preferences.

The registerDefaults: method does not actually set the value for the preferences. It simply says “if you call objectForKey for a specific preference, and is has not yet been explicitly set using setObject:, then return this default value”. I was getting caught up thinking that registerDefaults: actually set and stored the preferences (if they had not yet been set/stored). This is not the case. The registerDefaults:method will not overwrite an already stored preference, but it will “overwrite” a previously set default preference.

If you want to store a unique identifier for your user in their preferences, you need to explicitly check for the existence and set it appropriately.

NSString *existingUUID = [defaults objectForKey:@"UUID"];
if (existingUUID == nil){
  CFUUIDRef uuidObject = CFUUIDCreate(kCFAllocatorDefault);
  NSString *uuidStr = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidObject);
  CFRelease(uuidObject);
  [defaults setObject:uuidStr forKey:@"UUID"];
}
NSLog(@"UUID: %@", [defaults objectForKey:@"UUID"]);

Here we are getting the value for the “UUID” preference. We check if the value returned is nil. If it is nil, then we have never created it before, so we will create a new UUID and store this in the NSUserDefaults file.

I was getting stuck on this previously because I was using the registerDefaults: and was expecting the value to stick after first launching the application. This was not the case, as a new UUID was being returned each time I would call objectForKey:@"UUID". Again, I was not explicitly setting the value as I have done above, which is the correct approach.

I hope that helps for anyone else that might get tripped up the same way.