2009-02-24 8 views
13

Quiero realizar la misma acción sobre varios objetos almacenados en un NSSet.Cocoa NSArray/NSSet: -makeObjectsPerformSelector: frente a la enumeración rápida

Mi primer intento estaba usando una enumeración rápida:

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

que funciona bastante bien. Entonces pensé en:

[mySetOfObjects makeObjectsPerformSelector:@selector(action)]; 

Y ahora, no sé cuál es la mejor opción. Por lo que yo entiendo, las dos soluciones son equivalentes. ¿Pero hay argumentos para preferir una solución sobre la otra?

Respuesta

21

Yo discutiría el uso de makeObjectsPerformSelector, ya que permite que el objeto NSSet se encargue de su propia indexación, bucle y envío de mensajes. Las personas que escribieron el código NSSet probablemente conocerán la mejor manera de implementar ese bucle en particular.

En el peor de los casos, simplemente implementarían exactamente el mismo bucle, y todo lo que obtendrás es un código ligeramente más limpio (sin necesidad del bucle adjunto). En el mejor de los casos, hicieron algunas optimizaciones internas y el código realmente se ejecutará más rápido.

El tema se menciona brevemente en el documento Code Speed Performance de Apple, en la sección titulada "Unrolling Loops".

Si le preocupa el rendimiento, lo mejor que puede hacer es configurar un programa rápido que realice algún selector en los objetos de un conjunto. Haz que se ejecute varios millones de veces y cronometra la diferencia entre los dos casos diferentes.

+0

Gracias por el enlace, ¡no sabía este documento! Como dices, la sección "Desenrollar bucles" indica claramente que los desarrolladores de Cocoa han realizado optimizaciones internas con -makeObjectsPerformSelector: – mouviciel

+0

Me complace. Hay algunas cosas interesantes allí. –

2

makeObjectsPerformSelector: puede ser un poco más rápido, pero dudo que haya una diferencia práctica el 99% del tiempo. Aunque es un poco más conciso y legible, lo usaría por esa razón.

4

No utilizaría makeObjectsPerformSelector por la sencilla razón de que es el tipo de llamada que no se ve con frecuencia. He aquí por qué, por ejemplo, necesito agregar código de depuración ya que la matriz está enumerada, y realmente no puedes hacer eso con makeObjectsPerformSelector a menos que cambies la forma en que funciona el código en el modo de lanzamiento, que es un verdadero no no.

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

yo también se presentó con esta pregunta. Encuentro en la documentación de Apple "Colecciones Programación Temas" en "Sets: Unordered Collections of Objects" lo siguiente:

El método objectEnumerator NSSet permite que atraviesan los elementos del conjunto uno por uno. Y themakeObjectsPerformSelector: y makeObjectsPerformSelector: withObject: métodos proporcionan para enviar mensajes a objetos individuales en el conjunto. En la mayoría de los casos, la enumeración rápida debe ser utilizada porque es más rápida y más flexible que utilizando un NSEnumerator o el método makeObjectsPerformSelector: . Para obtener más información sobre la enumeración, consulte "Enumeración: atravesando elementos de una colección ."

Esto me lleva a creer que Fast Enumeration sigue siendo el medio más eficiente para esta aplicación.

1

Si la velocidad pura es el único problema (es decir, está creando un motor de representación donde cada ciclo de CPU pequeño cuenta), la forma más rápida de iterar a través de cualquiera de los objetos NSCollection (desde iOS 5.0 ~ 6.0) es varios métodos "enumerateObjectsUsingBlock". No tengo idea de por qué esto es así, pero lo probé y este parece ser el caso ...

Escribí pequeñas pruebas creando colecciones de cientos de miles de objetos que tienen cada uno un método que suma una simple matriz de enteros . Cada una de esas colecciones se vio forzada a realizar varios tipos de iteraciones (para bucle, enumeración rápida, makeObjectsPerformSelector y enumerateObjectsUsingBlock) millones de veces, y en casi todos los casos los métodos "enumerateObjectsUsingBlock" ganaron con facilidad en el transcurso de las pruebas.

El único momento en que esto no era cierto fue cuando la memoria comenzó a llenarse (cuando empecé a correr con millones de objetos), después de lo cual comenzó a perder a "makeObjectsPerformSelector".

Disculpa, no tomé una instantánea del código, pero es una prueba muy simple de ejecutar, recomiendo probarlo y compruébalo por ti mismo. :)

Cuestiones relacionadas