【问题标题】:Shuffling Letters in an NSString in Objective-C在 Objective-C 中的 NSString 中洗牌
【发布时间】:2011-04-10 14:30:57
【问题描述】:

我已经编写了这个函数,它可以对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;
}

【问题讨论】:

    标签: objective-c nsstring shuffle


    【解决方案1】:

    不使用字符数组的@dreamlax 代码的变体。肯定没有那么高效。但它没有 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];
    }
    

    【讨论】:

      【解决方案2】:

      最好将字符串的内容复制到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 倍)。

      【讨论】:

      • 谢谢!绝对是一个更好的解决方案。一个问题实际上是你不能使用 NSUIntegers,因为 -- on 0 会导致一个非常大的数字,而不是 -1,因为它是无符号的。我让它使用整数和保留来工作。在这种情况下,您认为显式保留还是分配更可取?
      • @jkeesh:关于无符号整数的要点。关于显式分配,它取决于目标平台。如果你的目标是 iPhone,有人说当你可以优雅地避免自动释放池时,但对于 Mac OS X(即内存比 iPhone 多得多的系统),它不会产生明显的差异。就个人而言,我总是明确分配而不是用retain 来对抗autorelease,但结果都是一样的。
      • 在这个国际化的时代,你不能假设一个 unichar 映射到一个字符。
      • @JeremyP:这就是我列出的第一个陷阱。
      • @dreamlax 你能用这个方法和 NSMutableString 代替 char 数组来避免 Unicode 问题吗?不确定在性能方面会付出什么代价。
      猜你喜欢
      • 2010-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-17
      相关资源
      最近更新 更多