Andrew Johnson
Andrew Johnson

Reputation: 13286

Is this a good way to generate a random string on iPhone?

Here's the code I came up with:

NSString *randomString = @"";
for (int x=0;x<NUMBER_OF_CHARS;x++) {
  randomString = [randomString stringByAppendingFormat:@"%c", (char)(65 + (arc4random() % 25))];
}
return randomString;

EDIT:

To answer the comments:

1) I'm mostly concerned with brevity of code.

2) I also wonder if this is secure against guessing the string, and/or proof against collisions, if NUMBER_OF_CHARS is a high number (say 40) - not for this application, but in other cases.

3) Also, is there is a faster way if I want to make a ton of strings some day? This seems like it will be slow, since it makes an object each time through the loop.

Upvotes: 7

Views: 5710

Answers (5)

Manav
Manav

Reputation: 10314

Another variant to the existing answers. I am posting this because it (seems) to be better performance wise, as it makes a single call to the ARC4 API.

NSString *random32CharacterString() {
    static const int N = 32; // must be even

    uint8_t buf[N/2];
    char sbuf[N];
    arc4random_buf(buf, N/2);
    for (int i = 0; i < N/2; i += 1) {
        sprintf (sbuf + (i*2), "%02X", buf[i]);
    }    
    return [[NSString alloc] initWithBytes:sbuf length:N encoding:NSASCIIStringEncoding];
}

Upvotes: 0

Jody Hagins
Jody Hagins

Reputation: 28349

FWIW, I'd favor Vincent Gable's suggestion of using a UUID. If you are set on the suggested algorithms, you can get a little bit more variance by using something like this variant of nielsbot's code (just replace the string of characters with whatever you want to include as part of your random strings)...

const NSUInteger NUMBER_OF_CHARS = 40 ;
NSString * CreateRandomString()
{
    static char const possibleChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    unichar characters[NUMBER_OF_CHARS];
    for( int index=0; index < NUMBER_OF_CHARS; ++index )
    {
        characters[ index ] = possibleChars[arc4random_uniform(sizeof(possibleChars)-1)];
    }

    return [ NSString stringWithCharacters:characters length:NUMBER_OF_CHARS ] ;
}

Upvotes: 4

Vincent Gable
Vincent Gable

Reputation: 3465

You might also consider using a UUID, since they're pretty well studied and widely used. I would probably start there before trying to guarantee the probability of collisions in my hand-rolled solution.

Upvotes: 2

nielsbot
nielsbot

Reputation: 16022

Here's a fast way to do this, if you will be doing this a lot

const NSUInteger NUMBER_OF_CHARS = 40 ;

NSString * CreateRandomString()
{
    unichar characters[NUMBER_OF_CHARS];
    for( int index=0; index < NUMBER_OF_CHARS; ++index )
    {
        characters[ index ] = 'A' + arc4random_uniform(26) ;
    }

    return [ NSString stringWithCharacters:characters length:NUMBER_OF_CHARS ] ;
}

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726509

If NUMBER_OF_CHARS is compile-time constant, you can speed up your code by avoiding repeated object creation. You can make your program shorter by one line, too:

char data[NUMBER_OF_CHARS];
for (int x=0;x<NUMBER_OF_CHARS;data[x++] = (char)('A' + (arc4random_uniform(26))));
return [[NSString alloc] initWithBytes:data length:NUMBER_OF_CHARS encoding:NSUTF8StringEncoding];

As far as I know, arc4random_uniform should be good enough for cryptographic applications, but you may need to consult a cryptography expert if the data that you are planning to protect is of high value to you or especially to your clients.

EDIT : Edited in response to nielsbot's comment.

Upvotes: 9

Related Questions