2009-02-24 12 views
13

Ich möchte die gleiche Aktion über mehrere Objekte in einer gespeicherten durchführen.Cocoa NSArray/NSSet: -makeObjectsPerformSelector: vs. schnelle Aufzählung

Mein erster Versuch wurde mit einer schnellen Auszählung:

for (id item in mySetOfObjects) 
    [item action]; 

was ziemlich gut funktioniert. Dann dachte ich:

[mySetOfObjects makeObjectsPerformSelector:@selector(action)]; 

Und jetzt weiß ich nicht, was die beste Wahl ist. Soweit ich verstehe, sind die beiden Lösungen gleichwertig. Aber gibt es Argumente für die Bevorzugung einer Lösung gegenüber der anderen?

Antwort

21

Ich würde für die Verwendung makeObjectsPerformSelector argumentieren, da es das NSSet-Objekt ermöglicht, sich um seine eigene Indizierung, Schleifen und Nachrichtenverteilung zu kümmern. Die Leute, die den NSSet-Code geschrieben haben, kennen am ehesten den besten Weg, um diese spezielle Schleife zu implementieren.

Im schlimmsten Fall würden sie einfach die exakt gleiche Schleife implementieren, und alles, was Sie gewinnen, ist etwas sauberer Code (keine Notwendigkeit für die umschließende Schleife). Im besten Fall haben sie einige interne Optimierungen vorgenommen und der Code wird tatsächlich schneller laufen.

Das Thema wird in Apples Code Speed Performance Dokument, in dem Abschnitt mit dem Titel "Unrolling Loops" kurz erwähnt.

Wenn Sie sich Sorgen um die Leistung machen, sollten Sie am besten ein schnelles Programm einrichten, das eine Auswahl an Objekten in einem Set ausführt. Lassen Sie es mehrere Millionen Mal laufen und legen Sie den Unterschied zwischen den zwei verschiedenen Fällen fest.

+0

Danke für den Link, ich kannte dieses Dokument nicht! Wie Sie sagen, der Abschnitt "Unrolling Loops" besagt eindeutig, dass Cocoa-Entwickler interne Optimierungen mit -makeObjectsPerformSelector vorgenommen haben: – mouviciel

+0

Ich freue mich. Da sind einige interessante Dinge drin. –

2

makeObjectsPerformSelector: könnte etwas schneller sein, aber ich bezweifle, dass es in 99% der Fälle einen praktischen Unterschied geben wird. Es ist ein wenig prägnanter und lesbarer, aber ich würde es aus diesem Grund verwenden.

4

Ich würde makeObjectsPerformSelector nicht aus dem einfachen Grund verwenden, dass es die Art von Anruf ist, die Sie nicht allzu oft sehen. Hier ist, warum zum Beispiel - ich muss Debugging-Code hinzufügen, wie das Array aufgezählt wird, und Sie können das wirklich nicht mit makeObjectsPerformSelector tun, wenn Sie ändern, wie der Code im Freigabemodus funktioniert, die ein echtes Nein ist.

for (id item in mySetOfObjects) 
{ 
    #if MY_DEBUG_BUILD 
    if ([item isAllMessedUp]) 
     NSLog(@"we found that wily bug that has been haunting us"); 
    #endif 

    [item action]; 
} 

--Tom

7

Auch ich war mit dieser Frage präsentiert. Ich finde in der Apple-Dokumentation „Sammlungen Programmierung Themen“ unter „Sets: Unordered Collections of Objects“ folgendes:

Die NSSet Methode objectEnumerator lässt Sie Elemente des Satzes ein durch eine durchqueren. Und themakeObjectsPerformSelector: und makeObjectsPerformSelector: withObject: Methoden bieten zum Senden von Nachrichten an einzelne Objekte in der Menge. In in den meisten Fällen sollte schnelle Aufzählung verwendet werden, weil es schneller ist und mehr flexibel als mit einem NSEnumerator oder die makeObjectsPerformSelector: Methode. Weitere Informationen zur Aufzählung finden Sie unter "Aufzählung: Durchlaufen einer Collection Elements."

Das lässt mich glauben, dass Fast Enumeration immer noch das effizienteste Mittel für diese Anwendung ist.

1

Wenn reine Geschwindigkeit das einzige Problem ist (dh Sie erstellen eine Rendering-Engine, bei der jeder kleine CPU-Zyklus zählt), ist die schnellste Möglichkeit, eines der NSCollection-Objekte (ab iOS 5.0 ~ 6.0) zu durchlaufen verschiedene "enumerateObjectsUsingBlock" Methoden. Ich habe keine Ahnung, warum das ist, aber ich habe es getestet und das scheint der Fall zu sein ...

Ich schrieb kleinen Test erstellen Sammlungen von Hunderttausenden von Objekten, die jeweils eine Methode, die eine einfache Array von Ints summiert . Jede dieser Sammlungen wurde gezwungen, die verschiedenen Arten der Iteration (for-Schleife, schnelle Enumeration, makeObjectsPerformSelector und enumerateObjectsUsingBlock) millionenfach durchzuführen, und in fast allen Fällen gewann die Methode "enumerateObjectsUsingBlock" im Laufe der Tests gut.

Das einzige Mal, wenn dies nicht der Fall war, als Speicher zu füllen begann (wenn ich es mit Millionen begann zu laufen von Objekten), wonach es begann zu „makeObjectsPerformSelector“ zu verlieren.

Es tut mir leid, dass ich keinen Schnappschuss des Codes gemacht habe, aber es ist ein sehr einfacher Test, ich empfehle es sehr, es zu versuchen und selbst zu sehen. :)

Verwandte Themen