objective-c selector dynamic-languages method-dispatch

objective c - Usando-performSelector: versus solo llamar al método



objective-c dynamic-languages (5)

Todavía soy un poco nuevo en Objective-C y me pregunto ¿cuál es la diferencia entre las dos afirmaciones siguientes?

[object performSelector:@selector(doSomething)]; [object doSomething];


@ennuikiller es perfecto. Básicamente, los selectores generados dinámicamente son útiles cuando no se conoce (y generalmente no se puede) el nombre del método al que se llama cuando se compila el código.

Una diferencia clave es que -performSelector: y los amigos (incluidas las variantes de subprocesos múltiples y diferidos ) son algo limitados en el sentido de que están diseñados para su uso con métodos con 0-2 parámetros. Por ejemplo, llamar a -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation: con 6 parámetros y devolver NSString es bastante difícil de manejar, y no es compatible con los métodos proporcionados.


Básicamente performSelector le permite determinar dinámicamente qué selector llamar a un selector en el objeto dado. En otras palabras, el selector no necesita determinarse antes del tiempo de ejecución.

Por lo tanto, aunque estos son equivalentes:

[anObject aMethod]; [anObject performSelector:@selector(aMethod)];

La segunda forma te permite hacer esto:

SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation(); [anObject performSelector: aSelector];

antes de enviar el mensaje


Hay otra diferencia sutil entre los dos.

[object doSomething]; // is executed right away [object performSelector:@selector(doSomething)]; // gets executed at the next runloop

Aquí está el extracto de la documentación de Apple

"performSelector: withObject: afterDelay: realiza el selector especificado en el subproceso actual durante el siguiente ciclo de ciclo de ejecución y después de un período de retardo opcional. Debido a que espera hasta el siguiente ciclo de ciclo de ejecución para realizar el selector, estos métodos proporcionan un mini retardo automático desde el código que se está ejecutando actualmente. Varios selectores en cola se ejecutan uno tras otro en el orden en que se pusieron en cola ".


Los selectores son un poco como indicadores de función en otros idiomas. Los usa cuando no sabe en tiempo de compilación a qué método desea llamar en tiempo de ejecución. Además, al igual que los punteros de función, solo encapsulan la parte de invocación del verbo. Si el método tiene parámetros, deberá pasarlos también.

Una NSInvocation sirve para un propósito similar, excepto que vincula más información. No solo incluye la parte del verbo, también incluye el objeto objetivo y los parámetros. Esto es útil cuando desea llamar a un método en un objeto particular con parámetros particulares, no ahora sino en el futuro. Puede construir una NSInvocation adecuada y NSInvocation más tarde.


Para este ejemplo muy básico en la pregunta,

[object doSomething]; [object performSelector:@selector(doSomething)];

no hay diferencia en lo que va a suceder. doSomething se ejecutará sincrónicamente por objeto. Solo "doSomething" es un método muy simple, que no devuelve nada, y no requiere ningún parámetro.

¿era algo un poco más complicado, como:

(void)doSomethingWithMyAge:(NSUInteger)age;

las cosas se complicarían, porque [object doSomethingWithMyAge: 42];

ya no se puede llamar con ninguna variante de "performSelector", porque todas las variantes con parámetros solo aceptan parámetros de objeto.

El selector aquí sería "doSomethingWithMyAge:" pero cualquier intento de

[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];

simplemente no compilará pasar un NSNumber: @ (42) en lugar de 42, tampoco ayudaría, porque el método espera un tipo de C básico, no un objeto.

Además, hay variantes de performSelector de hasta 2 parámetros, no más. Mientras que los métodos muchas veces tienen muchos más parámetros.

Descubrí que, aunque hay variantes sincrónicas de performSelector:

- (id)performSelector:(SEL)aSelector; - (id)performSelector:(SEL)aSelector withObject:(id)object; - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

Siempre devuelvo un objeto, también pude devolver un BOOL o NSUInteger simple, y funcionó.

Uno de los dos usos principales de performSelector es componer dinámicamente el nombre del método que desea ejecutar, como se explicó en una respuesta anterior. Por ejemplo

SEL method = NSSelectorFromString([NSString stringWithFormat:@"doSomethingWithMy%@:", @"Age"); [object performSelector:method];

El otro uso es enviar de forma asíncrona un mensaje al objeto, que se ejecutará más tarde en el runloop actual. Para esto, hay varias otras variantes de performSelector.

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes; - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay; - (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes; - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array; - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array; - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait; - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;

(Sí, los reuní en varias categorías de clase de Fundación, como NSThread, NSRunLoop y NSObject)

Cada una de las variantes tiene su propio comportamiento especial, pero todas comparten algo en común (al menos cuando waitUntilDone está establecido en NO). La llamada "performSelector" volverá inmediatamente, y el mensaje a objeto solo se pondrá en el runloop actual después de un tiempo.

Debido a la ejecución retrasada, naturalmente no hay valor de retorno disponible del método del selector, de ahí el valor de retorno (vacío) en todas estas variantes asincrónicas.

Espero haber cubierto esto de alguna manera ...