Usando-performSelector: vs. simplemente llamando al método


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

[object performSelector:@selector(doSomething)]; 

[object doSomething];
Author: Keavon, 2009-09-29

5 answers

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

Así, aunque estos son equivalentes:

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

La segunda forma le permite hacer esto:

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

Antes de enviar el mensaje.

 185
Author: ennuikiller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-29 18:25:05

@ennuikiller es perfecto. Básicamente, los selectores generados dinámicamente son útiles para cuando no sabes (y normalmente no puedes) el nombre del método al que llamarás cuando compiles el código.

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

 11
Author: Quinn Taylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-29 16:01:42

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 será ejecutado sincrónicamente por object. Solo "doSomething" es un método muy simple, que no devuelve nada, y no requiere ningún parámetro.

Si fuera 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 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.

He encontrado fuera de que aunque las variantes síncronas 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 simple o NSUInteger, 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 asincrónicamente un mensaje a object, que se ejecutará más adelante 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í de varias categorías de clases Foundation, 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 se establece en NO). La llamada" performSelector " regresaría inmediatamente, y el mensaje a object solo se colocará en el runloop actual después de algún tiempo.

Debido al retraso en la ejecución - naturalmente no el valor de retorno está disponible desde el método del selector, de ahí el valor de retorno - (void) en todas estas variantes asíncronas.

Espero haber cubierto esto de alguna manera...

 10
Author: Motti Shneor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-03 21:52:15

Los selectores son un poco como punteros 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 verbal de la invocación. Si el método tiene parámetros, también tendrá que pasarlos.

Un NSInvocation sirve para un propósito similar, excepto que une más información. No solo incluye la parte del verbo, también incluye el objeto de destino 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. Puedes construir un NSInvocation apropiado y dispararlo más tarde.

 3
Author: Daniel Yankowsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-29 16:58:02

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 bucle de ejecución y después de un período de retardo opcional. Debido a que espera hasta el siguiente ciclo de bucle de ejecución para realizar el selector, estos métodos proporcionan un mini retardo automático del código que se ejecuta actualmente. Múltiples selectores en cola se realizan uno después de otro en el orden que estaban en cola."

 -7
Author: avi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-05 17:38:06