Search code examples
objective-ciosuniqueidentifierudid

How to implement a basic voting mechanism in iOS that prevents duplicate votes?


I am showcasing content in my iOS app and I would like users to be able to vote. Instead of implementing a complicated "register a username" functionality, I just want a user to be able to upvote.
In the World of web development I could prevent duplicate votes by using the IP address of the client.

How can I make a simple voting system that allows a user to be only able to vote up a post once and not worry about duplicates?


Solution

  • Dont use uniqueIdentifier as Apple has stated:

    Deprecated in iOS 5.0

    uniqueIdentifier

    An alphanumeric string unique to each device based on various hardware details. (read-only) (Deprecated in iOS 5.0. Instead, create a unique identifier specific to your app.)

    Instead, I would suggest changing over from uniqueIdentifier to this open source library (2 simple categories really). It utilizes the device’s MAC Address along with the App Bundle Identifier to generate a unique ID in your applications that can be used as a UDID replacement.

    Keep in mind that unlike the UDID this number will be different for every app.

    You simply need to import the included NSString and UIDevice categories and call:

    #import "UIDevice+IdentifierAddition.h"
    #import "NSString+MD5Addition.h"
    NSString *iosFiveUDID = [[UIDevice currentDevice] uniqueDeviceIdentifier]
    

    You can find it on Github here:

    https://github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5


    Heres the code (just the .m files - check the github project for the headers):

    UIDevice+IdentifierAddition.m

    #import "UIDevice+IdentifierAddition.h"
    #import "NSString+MD5Addition.h"
    
    #include <sys/socket.h> // Per msqr
    #include <sys/sysctl.h>
    #include <net/if.h>
    #include <net/if_dl.h>
    
    @interface UIDevice(Private)
    
    - (NSString *) macaddress;
    
    @end
    
    @implementation UIDevice (IdentifierAddition)
    
    ////////////////////////////////////////////////////////////////////////////////
    #pragma mark -
    #pragma mark Private Methods
    
    // Return the local MAC addy
    // Courtesy of FreeBSD hackers email list
    // Accidentally munged during previous update. Fixed thanks to erica sadun & mlamb.
    - (NSString *) macaddress{
        
        int                 mib[6];
        size_t              len;
        char                *buf;
        unsigned char       *ptr;
        struct if_msghdr    *ifm;
        struct sockaddr_dl  *sdl;
        
        mib[0] = CTL_NET;
        mib[1] = AF_ROUTE;
        mib[2] = 0;
        mib[3] = AF_LINK;
        mib[4] = NET_RT_IFLIST;
        
        if ((mib[5] = if_nametoindex("en0")) == 0) {
            printf("Error: if_nametoindex error\n");
            return NULL;
        }
        
        if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
            printf("Error: sysctl, take 1\n");
            return NULL;
        }
        
        if ((buf = malloc(len)) == NULL) {
            printf("Could not allocate memory. error!\n");
            return NULL;
        }
        
        if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
            printf("Error: sysctl, take 2");
            return NULL;
        }
        
        ifm = (struct if_msghdr *)buf;
        sdl = (struct sockaddr_dl *)(ifm + 1);
        ptr = (unsigned char *)LLADDR(sdl);
        NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 
                               *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
        free(buf);
        
        return outstring;
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    #pragma mark -
    #pragma mark Public Methods
    
    - (NSString *) uniqueDeviceIdentifier{
        NSString *macaddress = [[UIDevice currentDevice] macaddress];
        NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];  
        NSString *stringToHash = [NSString stringWithFormat:@"%@%@",macaddress,bundleIdentifier];
        NSString *uniqueIdentifier = [stringToHash stringFromMD5];  
        return uniqueIdentifier;
    }
    
    - (NSString *) uniqueGlobalDeviceIdentifier{
        NSString *macaddress = [[UIDevice currentDevice] macaddress];
        NSString *uniqueIdentifier = [macaddress stringFromMD5];    
        return uniqueIdentifier;
    }
    
    @end
    

    NSString+MD5Addition.m:

    #import "NSString+MD5Addition.h"
    #import <CommonCrypto/CommonDigest.h>
    
    @implementation NSString(MD5Addition)
    
    - (NSString *) stringFromMD5{
        
        if(self == nil || [self length] == 0)
            return nil;
        
        const char *value = [self UTF8String];
        
        unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
        CC_MD5(value, strlen(value), outputBuffer);
        
        NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
        for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
            [outputString appendFormat:@"%02x",outputBuffer[count]];
        }
        return [outputString autorelease];
    }
    
    @end