Ich suche nach der Standardsprache, um über ein NSArray zu iterieren. Mein Code muss für OS X 10.4+ geeignet sein.
quelle
Ich suche nach der Standardsprache, um über ein NSArray zu iterieren. Mein Code muss für OS X 10.4+ geeignet sein.
Der allgemein bevorzugte Code für 10.5 + / iOS.
for (id object in array) {
// do something with object
}
Dieses Konstrukt wird verwendet, um Objekte in einer Sammlung aufzulisten, die dem NSFastEnumeration
Protokoll entspricht. Dieser Ansatz hat einen Geschwindigkeitsvorteil, da er Zeiger auf mehrere Objekte (die über einen einzelnen Methodenaufruf erhalten wurden) in einem Puffer speichert und diese durchläuft, indem er mithilfe der Zeigerarithmetik durch den Puffer fährt. Dies ist viel schneller als -objectAtIndex:
jedes Mal durch die Schleife aufzurufen .
Es ist auch erwähnenswert, dass Sie zwar technisch gesehen eine For-In-Schleife verwenden können, um eine zu durchlaufen NSEnumerator
, ich jedoch festgestellt habe, dass dies praktisch den gesamten Geschwindigkeitsvorteil einer schnellen Aufzählung zunichte macht. Der Grund dafür ist , dass der Standard NSEnumerator
Implementierung von -countByEnumeratingWithState:objects:count:
Orten nur ein Objekt in dem Puffer bei jedem Aufruf.
Ich habe dies in radar://6296108
(Die schnelle Aufzählung von NSEnumerators ist träge) gemeldet, aber es wurde als Nicht zu beheben zurückgegeben. Der Grund dafür ist, dass eine schnelle Aufzählung eine Gruppe von Objekten vorab abruft und Sie nur bis zu einem bestimmten Punkt im Aufzähler aufzählen möchten (z. B. bis ein bestimmtes Objekt gefunden wurde oder die Bedingung erfüllt ist) und nach dem Ausbruch denselben Aufzähler verwenden In der Schleife würden häufig mehrere Objekte übersprungen.
Wenn Sie für OS X 10.6 / iOS 4.0 und höher codieren, haben Sie auch die Möglichkeit, blockbasierte APIs zum Auflisten von Arrays und anderen Sammlungen zu verwenden:
[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
// do something with object
}];
Sie können auch -enumerateObjectsWithOptions:usingBlock:
und NSEnumerationConcurrent
und oder oder NSEnumerationReverse
als Optionsargument verwenden und übergeben .
Die Standardsprache für Pre-10.5 ist die Verwendung einer NSEnumerator
und einer while-Schleife wie folgt :
NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
// do something with object
}
Ich empfehle es einfach zu halten. Es ist unflexibel, sich an einen Array-Typ zu binden, und die angebliche Geschwindigkeitssteigerung bei der Verwendung -objectAtIndex:
ist ohnehin unbedeutend für die Verbesserung bei schneller Aufzählung auf 10.5+. (Bei der schnellen Aufzählung wird tatsächlich eine Zeigerarithmetik für die zugrunde liegende Datenstruktur verwendet, und der größte Teil des Methodenaufrufaufwands entfällt.) Eine vorzeitige Optimierung ist niemals eine gute Idee - sie führt zu unübersichtlichem Code, um ein Problem zu lösen, das ohnehin nicht Ihr Engpass ist.
Bei der Verwendung -objectEnumerator
können Sie ganz einfach zu einer anderen aufzählbaren Sammlung wechseln (z. B. zu NSSet
, Schlüssel in einer NSDictionary
usw.) oder sogar zu wechseln, -reverseObjectEnumerator
um ein Array rückwärts aufzulisten, ohne dass andere Codeänderungen erforderlich sind. Wenn sich der Iterationscode in einer Methode befindet, können Sie sogar eine übergeben, NSEnumerator
und der Code muss sich nicht einmal darum kümmern, was er iteriert. Außerdem NSEnumerator
behält ein (zumindest die vom Apple-Code bereitgestellten) die aufgezählte Sammlung bei, solange mehr Objekte vorhanden sind, sodass Sie sich keine Gedanken darüber machen müssen, wie lange ein automatisch freigegebenes Objekt vorhanden sein wird.
Vielleicht ist das Größte, wovor Sie eine NSEnumerator
(oder schnelle Aufzählung) schützt, dass sich eine veränderbare Sammlung (Array oder andere) ohne Ihr Wissen unter Ihnen ändert, während Sie sie aufzählen. Wenn Sie über den Index auf die Objekte zugreifen, können seltsame Ausnahmen oder Fehler auftreten (häufig lange nach dem Auftreten des Problems), deren Debugging schrecklich sein kann. Die Aufzählung mit einer der Standard-Redewendungen hat ein "Fail-Fast" -Verhalten, sodass sich das Problem (verursacht durch falschen Code) sofort manifestiert, wenn Sie versuchen, auf das nächste Objekt zuzugreifen, nachdem die Mutation aufgetreten ist. Wenn Programme komplexer und multithreaded werden oder sogar von etwas abhängen, das durch Code von Drittanbietern geändert werden kann, wird fragiler Aufzählungscode zunehmend problematisch. Verkapselung und Abstraktion FTW! :-)
for (id object in array)
es eine Möglichkeit, auch den aktuellen Index des Objekts im Array zu bestimmen, oder muss ein separater Zähler eingefügt werden?for
Schleife wie diese:for(;;) { id object = [ e nextObject ] ; if ( !e ) { break ; } ... your loop operation ... }
Für OS X 10.4.x und frühere Versionen:
Für OS X 10.5.x (oder iPhone) und darüber hinaus:
quelle
for (NSUInteger i = 0, count = [myArray count]; i < count; i++)
ist wahrscheinlich die effizienteste und prägnanteste, die Sie für diesen Ansatz erhalten.Die Ergebnisse des Tests und des Quellcodes sind unten aufgeführt (Sie können die Anzahl der Iterationen in der App festlegen). Die Zeit ist in Millisekunden angegeben, und jeder Eintrag ist ein durchschnittliches Ergebnis der fünf- bis zehnmaligen Ausführung des Tests. Ich fand heraus, dass es im Allgemeinen auf 2-3 signifikante Stellen genau ist und danach mit jedem Lauf variieren würde. Dies ergibt eine Fehlerquote von weniger als 1%. Der Test lief auf einem iPhone 3G, da dies die Zielplattform war, an der ich interessiert war.
Die von Cocoa bereitgestellten Klassen für die Verarbeitung von Datensätzen (NSDictionary, NSArray, NSSet usw.) bieten eine sehr schöne Schnittstelle für die Verwaltung von Informationen, ohne sich um die Bürokratie der Speicherverwaltung, Neuzuweisung usw. kümmern zu müssen. Dies ist natürlich mit Kosten verbunden . Ich denke, es ist ziemlich offensichtlich, dass die Verwendung eines NSArray von NSNumbers für einfache Iterationen langsamer sein wird als die Verwendung eines C-Arrays von Floats. Deshalb habe ich beschlossen, einige Tests durchzuführen, und die Ergebnisse waren ziemlich schockierend! Ich hatte nicht erwartet, dass es so schlimm wird. Hinweis: Diese Tests werden auf einem iPhone 3G durchgeführt, da dies die Zielplattform ist, an der ich interessiert war.
In diesem Test führe ich einen sehr einfachen Vergleich der Leistung bei wahlfreiem Zugriff zwischen einem C-Float * und einem NSArray von NSNumbers durch
Ich erstelle eine einfache Schleife, um den Inhalt jedes Arrays zusammenzufassen und mit mach_absolute_time () zu messen. Das NSMutableArray dauert durchschnittlich 400 mal länger !! (nicht 400 Prozent, nur 400 Mal länger! das sind 40.000% länger!).
Header:
// Array_Speed_TestViewController.h
// Array-Geschwindigkeitstest
// Erstellt von Mehmet Akten am 05/02/2009.
// Copyright MSA Visuals Ltd. 2009. Alle Rechte vorbehalten.
Implementierung:
// Array_Speed_TestViewController.m
// Array-Geschwindigkeitstest
// Erstellt von Mehmet Akten am 05/02/2009.
// Copyright MSA Visuals Ltd. 2009. Alle Rechte vorbehalten.
Von: memo.tv.
///////////////////////
Dies ist seit der Einführung von Blöcken verfügbar und ermöglicht das Iterieren eines Arrays mit Blöcken. Die Syntax ist nicht so gut wie die schnelle Aufzählung, aber es gibt eine sehr interessante Funktion: die gleichzeitige Aufzählung. Wenn die Aufzählungsreihenfolge nicht wichtig ist und die Jobs ohne Sperren parallel ausgeführt werden können, kann dies auf einem Mehrkernsystem zu einer erheblichen Beschleunigung führen. Mehr dazu im Abschnitt zur gleichzeitigen Aufzählung.
/////////// NSFastEnumerator
Die Idee hinter der schnellen Aufzählung besteht darin, den schnellen C-Array-Zugriff zu verwenden, um die Iteration zu optimieren. Es soll nicht nur schneller als der herkömmliche NSEnumerator sein, sondern Objective-C 2.0 bietet auch eine sehr präzise Syntax.
///////////////////
NSEnumerator
Dies ist eine Form der externen Iteration: [myArray objectEnumerator] gibt ein Objekt zurück. Dieses Objekt hat eine Methode nextObject, die wir in einer Schleife aufrufen können, bis sie nil zurückgibt
///////////////////
objectAtIndex: Aufzählung
Die Verwendung einer for-Schleife, die eine Ganzzahl erhöht, und das Abfragen des Objekts mit [myArray objectAtIndex: index] ist die grundlegendste Form der Aufzählung.
/////////////// Von: darkdust.net
quelle
Die drei Möglichkeiten sind:
quelle
Füge eine
each
Methode hinzuNSArray category
, du wirst sie sehr brauchenCode aus ObjectiveSugar
quelle
So deklarieren Sie ein Array von Zeichenfolgen und iterieren darüber:
quelle
Für Swift
quelle
Mach das :-
quelle