Mixing letters in NSString in Objective-C

I wrote this function that shuffles the contents of an NSString , and it seems to work, but from time to time it crashes. This may be a workaround, but I put the characters in the array, randomly change the elements in the array and then return the array back to the string.

I'm not sure what I'm doing is that it is unsafe, which leads to its collapse. I thought that maybe I am setting finalLettersString = result , but I also tried finalLettersString = [NSString stringWithString:result] , and that also fails. The reason I am confused is that it does not crash every time. I just press the shuffle button and sometimes it crashes. Any places I should see?

 /* This function shuffles the letters in the string finalLettersString */ -(IBAction)shuffleLetters:(id)sender{ int length = [finalLettersString length]; NSMutableArray * letters = [NSMutableArray arrayWithCapacity:length]; NSLog(@"final letters: %@", finalLettersString); for(int i = 0; i < length; i++){ char ch = [finalLettersString characterAtIndex:i]; NSLog(@"%c", ch); NSString * cur = [NSString stringWithFormat:@"%c", ch]; [letters insertObject:cur atIndex:i]; } NSLog(@"LETTERS:: %@", letters); for(int i = length - 1; i >= 0; i--){ int j = arc4random() % (i + 1); //NSLog(@"%d %d", i, j); //swap at positions i and j NSString * str_i = [letters objectAtIndex:i]; [letters replaceObjectAtIndex:i withObject:[letters objectAtIndex:j]]; [letters replaceObjectAtIndex:j withObject:str_i]; } NSLog(@"NEW SHUFFLED LETTERS %@", letters); NSString * result = @""; for(int i = 0; i < length; i++){ result = [result stringByAppendingString:[letters objectAtIndex:i]]; } NSLog(@"Final string: %@", result); finalLettersString = result; finalLetters.text = finalLettersString; } 
+6
objective-c nsstring shuffle
source share
2 answers

It is better to copy the contents of the string into a temporary unichar buffer and shuffle the contents of the buffer instead of creating a large number of small lines.

 NSUInteger length = [finalLettersString length]; if (!length) return; // nothing to shuffle unichar *buffer = calloc(length, sizeof (unichar)); [finalLettersString getCharacters:buffer range:NSMakeRange(0, length)]; for(int i = length - 1; i >= 0; i--){ int j = arc4random() % (i + 1); //NSLog(@"%d %d", i, j); //swap at positions i and j unichar c = buffer[i]; buffer[i] = buffer[j]; buffer[j] = c; } NSString *result = [NSString stringWithCharacters:buffer length:length]; free(buffer); // caution, autoreleased. Allocate explicitly above or retain below to // keep the string. finalLettersString = result; 

A few things you will need to observe:

  • Unicode strings can contain compound characters and surrogate pairs. Shuffling these objects is likely to result in an invalid string. While surrogate pairs are rare, it is easy to find that the é symbol consists of two characters (the base lowercase letter e and a combination of acute accent).

  • For large lines, this can cause memory problems, because you end up using 3 times more space than the original line (1 × for the original line, 2 × for the buffer used and 3 × for the new line, and then back down to 2 × when we free the buffer).

+8
source share

A variant of @dreamlax code that does not use a char array. Not so effective. But it has no problem with Unicode.

 NSMutableString *randomizedText = [NSMutableString stringWithString:currentText]; NSString *buffer; for (NSInteger i = randomizedText.length - 1, j; i >= 0; i--) { j = arc4random() % (i + 1); buffer = [randomizedText substringWithRange:NSMakeRange(i, 1)]; [randomizedText replaceCharactersInRange:NSMakeRange(i, 1) withString:[randomizedText substringWithRange:NSMakeRange(j, 1)]]; [randomizedText replaceCharactersInRange:NSMakeRange(j, 1) withString:buffer]; } 
+11
source share

All Articles