2009-07-03 10 views
1

Ich muss bestimmte Positionen in einem NSArray überprüfen, um zu sehen, ob sie bereits initialisiert wurden, aber ich habe Probleme. Ich habe versucht folgendes zu tun, aber es bringt meine Anwendung zum Absturz!Ermitteln, ob eine Position in Array bereits initiiert wurde

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

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

Was ist das Beste, dies zu tun? Ich habe schon einige Methoden wie isValid und solche Sachen ausprobiert!

Antwort

5

Sie ein paar Optionen hier:

Option 1: vorfüllen das Array mit Instanzen von , und verwenden Sie dann den von Dave DeLong in his answer angegebenen Code.

Option 2: (Ähnlich wie # 1) füllen Sie das Array mit Instanzen von NSMutableArray, und haben dann keinen zusätzlichen Code. (Wenn Sie vorfüllen möchten, können Sie dies auch tun).

Option 3: Füllen Sie das Array nicht vorab, sondern fügen Sie Elemente dynamisch nach Bedarf ein. Dies wird fast identisch mit einem vorab füllen, wenn die erste iLine nahe dem Maximum ist:

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

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

Option 4:

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

Wie: Verwenden Sie ein Wörterbuch, um die Liste der NSMutableArrays zu halten zu wählen:

Wenn der Höchstwert für iLine nicht enorm ist, würde ich mit Option # 2 gehen. Eine Handvoll NSMutableArrays initialisiert auf Null Kapazität wird sehr wenig Speicher aufnehmen.

Wenn der Höchstwert für iLine enorm ist, aber Sie erwarten, dass er nur spärlich aufgerufen wird (d. H., Nur wenige Werte von iLine werden jemals aufgerufen), sollten Sie Option 4 wählen. Dadurch ersparen Sie es sich, einen NSMutableArray mit Objekten zu füllen, die niemals benutzt werden. Der Aufwand zum Konvertieren des Zeichenfolgenwertsschlüssels für das Wörterbuch ist geringer als der Aufwand zum Erstellen all dieser Leerzeichen.

Wenn Sie nicht sicher sind, probieren Sie jede Option aus und profilieren Sie sie: messen Sie die Speicherauslastung und die Ausführungszeit. Wenn keine dieser Optionen funktioniert, müssen Sie möglicherweise komplexere Lösungen untersuchen, aber nur, wenn es sich als notwendig erweist.

Ein Wort der Warnung:

Der ursprüngliche Code, den Sie ein Speicherleck in der folgenden Zeile geschrieben hat:

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

Die NSMutableArray Objekte, die Sie hier initialisieren nie veröffentlicht. Wenn Sie [[NSMutableArray init] alloc] aufrufen, wird ein brandneues Objekt erstellt (mit einer Referenzzahl von eins). Die insertObject Methode fügt dann das neue Objekt zu arrAllBlocks und retains es (Erhöhung seiner Retain-Anzahl auf 2). Später, wenn Sie arrAllBlocks freigeben, wird das neue Array eine release Nachricht gesendet, aber das wird nur seine Retain-Anzahl auf eins wieder reduzieren. An diesem Punkt wird es im RAM bleiben, bis Ihr Programm beendet wird.

Das beste, was Sie hier tun können, ist stattdessen [NSMutableArray arrayWithCapacity:0] zu verwenden (wie ich in meinen Beispielen getan habe). Dies gibt eine neue NSMutableArray zurück, genauso wie Ihr Code, aber diese Instanz wurde bereits autoreleased. Auf diese Weise kann arrAllBlocks Besitz des neuen Objekts übernehmen und Sie können sicher sein, dass es bei Bedarf freigegeben wird.

4

Sie können nicht. NSArray (und seine Unterklasse NSMutableArray) erlauben es nicht, nil in das Array einzufügen. Das ist in der Dokumentation klar umrissen.

Wenn Sie aus irgendeinem Grund "leere" Werte in einem Array haben müssen, sollten Sie stattdessen [NSNull null] einfügen und danach testen. Aus der Dokumentation: "Die NSNull-Klasse definiert ein Singleton-Objekt, das zur Darstellung von Nullwerten in Auflistungsobjekten verwendet wird (die keine Nullwerte zulassen)."

UPDATE:

Dies bedeutet, dass Sie Ihren Code sehr einfach sich dies ändern könnte:

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, ok! Aber ich versuche, was Sie sagen, und noch nicht arbeiten =/ Ich brauche das, becouse die Anzahl der Objekte in arrAllBlocks, kann sich ändern! Also möchte ich diese Dynamik machen! Ich kann dafür sorgen, dass alle Instanzen erstellt werden, die ich brauche, aber es sieht ein wenig Hardcode aus! – baDa

+1

@Dave DeLong: Sie haben recht mit der Verwendung von NSNull-Objekten, aber baDa müsste sein Array mit ihnen vorher füllen, damit dies funktioniert. Wenn er das macht, kann er das Array genauso gut mit leeren NSMutableArrays füllen. Ich habe eine Antwort mit mehr Details gepostet. –

+0

@eJames: guter Punkt, und gute Antwort (ich habe es gewählt). NSNull wäre für den Fall, wenn er Indizes beibehalten möchte, aber immer noch bestimmte Positionen innerhalb seines Arrays "nil". =) –

1

Um zu überprüfen, für NSNull Sie einfach gegen den Zeiger vergleichen, da es ein Singleton ist:

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

ich die unansehnlichen Abgüsse ebenfalls entfernt. Casting ist in Objective-C selten notwendig. Es fügt normalerweise nur Rauschen hinzu und kann echte Fehler verbergen. Da es sich um Abstürze handelt, lohnt es sich, die Umwandlungen aus diesem Code zu entfernen und zuzuhören, was der Compiler darüber zu sagen hat.

Wenn der Compiler die Warnungen für ein Stück Code ignoriert, wird das zugrundeliegende Problem nicht beseitigt!

Verwandte Themen