7

我已经编写了这个函数,它对 a 的内容进行了洗牌NSString,它似乎可以工作,但它时不时地崩溃。这可能是一种迂回的方式,但我将字符放入数组中,随机交换数组中的元素,然后将数组转回字符串。

我不确定我在做什么是不安全的,这会导致它崩溃。我认为这可能是我正在设置finalLettersString = result,但我也尝试过,但finalLettersString = [NSString stringWithString:result]它也崩溃了。我感到困惑的原因是因为它不会每次都崩溃。我只是一直按随机播放按钮,有时它会崩溃。有什么地方值得看吗?

/* 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;
}
4

2 回答 2

11

@dreamlax 代码的一种变体,不使用 char 数组。肯定没有那么高效。但它没有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];
}
于 2011-09-01T21:58:50.467 回答
9

最好将字符串的内容复制到类型的临时缓冲区中unichar并打乱缓冲区的内容,而不是创建很多小字符串。

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;

您需要注意以下几点:

  1. Unicode 字符串可以包含复合字符和代理项对。随机播放这些内容很可能会导致无效字符串。虽然代理对很少见,但发现字符 é 由两个字符(基本小写字母 e 和组合的重音符号)组成的情况并不少见。

  2. 对于大字符串,它可能会导致内存问题,因为您最终使用的空间是原始字符串的 3 倍(原始字符串为 1 倍,我们使用的缓冲区为 2 倍,新字符串为 3 倍,然后返回释放缓冲区后变为 2 倍)。

于 2010-09-10T06:45:19.727 回答