2010-09-10 48 views
6

一個NSString我寫了這個功能,混洗NSString的內容,似乎工作,但每一個現在,然後崩潰。這可能是一種迂迴的方式,但是我將這些字符放入一個數組中,隨機交換數組中的元素,然後將數組轉換回字符串。洗牌字母在Objective-C的

我不知道我在做什麼是不安全的,這使得它崩潰。我認爲這是可能的,我設置finalLettersString = result,但我也試過finalLettersString = [NSString stringWithString:result]並且還崩潰。我感到困惑的原因是它不會每次都崩潰。我只是不停地按下shuffle按鈕,有時它會崩潰。我應該看的任何地方?

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

回答

8

這將是更好的字符串的內容複製到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×)。

+0

謝謝!絕對是一個更好的解決方案。其中一個問題實際上是你不能使用NSUInteger,因爲 - 在0上導致一個非常大的數字而不是-1,因爲它沒有簽名。我使用了整數並保留了它。在這種情況下,你認爲最好保留還是明確分配? – jkeesh 2010-09-10 07:25:08

+0

@jkeesh:關於無符號整數的好處。關於明確分配,它取決於目標平臺。如果你的目標iPhone,有人說,以避免自動釋放池時,你可以優雅地這樣做,但爲Mac OS X(即具有比iPhone更多的內存系統),它將使沒有明顯的區別。就我個人而言,我總是明確地分配,而不是用'retain'來抵抗'autorelease',但結果是一樣的。 – dreamlax 2010-09-10 07:29:46

+0

在這個國際化的時代,你不能假設一個unichar映射到一個角色。 – JeremyP 2010-09-10 07:45:02

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]; 
}