2009-07-03 45 views
1

我需要檢查NSArray中的特定位置以查看它們是否已被初始化,但我遇到了問題。我試圖做到以下,但它導致我的應用程序崩潰!檢測是否已經啓動了陣列中的一個位置

if ((NSMutableArray *)[arrAllBlocks objectAtIndex:iLine] == nil) 
{ 
    [arrAllBlocks insertObject:[[NSMutableArray alloc] init] atIndex:iLine]; 
} 

NSMutableArray *columArray = (NSMutableArray *)[arrAllBlocks 
               objectAtIndex:iLine]; 
[columArray insertObject:newBlock atIndex:iColumn]; 

什麼是最好做到這一點?我已經嘗試過一些方法,如isValid,以及類似的東西!

回答

5

您有幾種選擇在這裏:

選項1:預填充數組例如NSNull,然後使用Dave DeLong在his answer中給出的代碼。

選項2:(類似於#1)預填充陣列的實例爲NSMutableArray,然後根本沒有額外的代碼。 (如果你要預先填寫,你可以這樣做)。

選項3:不要預先填充數組,而是根據需要動態插入項目。這將是幾乎相同的預填充如果第一iLine是接近最大:

while([arrAllBlocks count] <= iLine) 
{ 
    [arrAllBlocks addObject:[NSMutableArray arrayWithCapacity:0]]; 
} 

NSMutableArray *columArray = (NSMutableArray *)[arrAllBlocks 
               objectAtIndex:iLine]; 
[columArray insertObject:newBlock atIndex:iColumn]; 

方案4:使用字典來維持的NSMutableArrays名單:

NSString *key = [NSString stringWithFormat:@"%d", iLine]; 
NSMutableArray *columnArray = [dictAllBlocks objectForKey:key]; 
if (columnArray == nil) 
{ 
    columnArray = [NSMutableArray arrayWithCapacity:0]; 
    [dictAllBlocks setObject:columnArray forKey:key]; 
} 

[columArray insertObject:newBlock atIndex:iColumn]; 

如何選擇:

如果iLine的最大值不是很大,我會選擇#2。少數初始化爲零容量的NSMutableArrays將佔用很少的內存。

如果iLine的最大值很大,但您期望它被稀疏訪問(即只有幾個值爲iLine將被訪問),那麼您應該使用選項#4。這將使您無需填寫NSMutableArray與永不使用的對象。轉換字典的字符串值鍵的開銷將小於創建所有這些空白的開銷。

如果您不確定,請嘗試每個選項並對它們進行配置:測量您的內存使用情況以及執行所需的時間。如果這兩個選項都不起作用,那麼您可能需要探索更復雜的解決方案,但只有在需要時纔會這樣做。

一個值得注意的問題:

,你貼在下面一行內存泄漏原代碼:

[arrAllBlocks insertObject:[[NSMutableArray alloc] init] atIndex:iLine]; 

,你在這裏初始化從未發佈的NSMutableArray對象。當您撥打[[NSMutableArray init] alloc]時,會創建一個全新的對象(引用計數爲1)。然後insertObject方法將該新對象添加到arrAllBlocksretains它(將其保留計數增加到2)。稍後,當您發佈arrAllBlocks時,新陣列將發送release消息,但這隻會將其保留次數再次減少爲1。在那個時候,它會一直存在於RAM中,直到你的程序退出。

這裏要做的最好的事情是使用[NSMutableArray arrayWithCapacity:0]來代替(正如我在我的例子中所做的那樣)。這將返回一個新的NSMutableArray,與您的代碼一樣,但此實例已爲autoreleased。這樣,arrAllBlocks可以獲得新對象的所有權,並且您可以確保它將在適當時候發佈。

4

你不能。 NSArray(及其子類NSMutableArray)不允許你在數組中插入nil。這在文檔中已清楚地概述。

如果出於某種原因需要在數組中有「空」值,那麼應該插入[NSNull null],然後測試它。從文檔:「NSNull類定義了一個單獨的對象,用於表示集合對象中的空值(不允許有零值)。」

UPDATE:

這意味着你可以很簡單地改變你的代碼如下:

if ([[arrAllBlocks objectAtIndex:iLine] isEqual:[NSNull null]]) { 
    [(NSMutableArray *)arrAllBlocks insertObject:[NSMutableArray array] atIndex:iLine]; 
} 
NSMutableArray *columnArray = (NSMutableArray *)[arrAllBlocks objectAtIndex:iLine]; 
[columnArray insertObject:newBlock atIndex:iColumn]; 
+0

Hummm,好的! 但是我嘗試了你所說的,但還沒有正常工作=/ 我需要這個,因爲arrAllBlocks中的對象數目可能會改變!所以我想要做那動態!我可以在此之前創建一個,並創建所需的所有實例,但它會顯示一些硬編碼! – baDa 2009-07-03 17:49:13

1

要檢查NSNull你可以簡單地比較反對的指針,因爲它是一個單例:

if ([NSNull null] == [arrAllBlocks objectAtIndex:iLine]) { 
    [arrAllBlocks insertObject:[NSMutableArray array] atIndex:iLine]; 
} 
NSMutableArray *columnArray = [arrAllBlocks objectAtIndex:iLine]; 
[columnArray insertObject:newBlock atIndex:iColumn]; 

我也去掉了難看的轉換。 Objective-C中很少需要鑄造。它通常只會增加噪音,並可以隱藏真正的錯誤。由於您遇到崩潰,因此應該從該代碼中移除強制轉換,並聽取編譯器告訴您的信息。

告訴編譯器忽略一段代碼的警告並不會導致它的根本問題消失!

相關問題