Cómo crear una "matriz de selectores"

82

Estoy usando el iPhone SDK (3.0) y estoy tratando de crear una matriz de selectores para invocar una variedad de métodos dentro de una clase.

Obviamente, estoy haciendo algo mal (creo que @selector no se considera una clase y, por lo tanto, meterlos en un NSArray no funciona).

Intenté esto, pero obviamente está mal.

¿Existe una forma sencilla de tener una matriz de selectores como esta? ¿O hay una mejor manera de iterar a través de una colección de métodos?

selectors = [NSArray arrayWithObjects:
                          @selector(method1),
                          @selector(method2),
                          @selector(method3),
                          @selector(method4),
                          @selector(method5),
                          @selector(method6),
                          @selector(method7), nil];

for (int i = 0; i < [selectors count]; i++) {
    if ([self performSelector:[selectors objectAtIndex:i]]) // do stuff;
}
usuario141146
fuente

Respuestas:

79

¿Podría almacenar cadenas y usar NSSelectorFromString?

De los documentos

NSSelectorFromString

Devuelve el selector con un nombre dado.

SEL NSSelectorFromString (
   NSString *aSelectorName
);
ciego
fuente
2
No es una solución adecuada para cuando solo se necesita una serie de selectores.
Aleks N.
1
NSPointerArrayes mejor.
DawnSong
43

Esto crea un objeto fuera del selector:

[NSValue valueWithPointer:@selector(x)]
DenNukem
fuente
2
¿Cómo haría para extraer el selector de esto para que lo use performSelector:?
Dean Kelly
3
@DeanKelly respondió aquí stackoverflow.com/questions/575055/… por terry franguiadakis
ABCD.ca
1
Se necesita un elenco de tipo, de la siguiente maneraSEL x = (SEL)selectorValue.pointerValue;
DawnSong
35

¿Por qué no usar simplemente una matriz C simple?

static const SEL selectors[] = {@selector(method1),
                                ....
                                @selector(method7)};

...

for (int i = 0; i < sizeof(selectors)/sizeof(selectors[0]); i++) {
  [self performSelector:selectors[i]];
  // ....
}
Kennytm
fuente
3
Bien, pero staticno es necesario aquí (el inicializador no es una constante en tiempo de compilación).
Aleks N.
12

También puede crear una matriz de NSInvocations. Esto es útil si necesita un argumento que vaya con su selector.

NSMethodSignature *sig = [[yourTarget class] instanceMethodSignatureForSelector:yourSEL];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig];
[inv setTarget:yourTarget];
[inv setSelector:yourSEL];
[inv setArgument:&yourObject atIndex:2]; // Address of your object
Morrowless
fuente
NSInvocation es demasiado caro.
DawnSong
1

Si la lista es estática, optaría por la solución de KennyTM, pero si necesita una matriz o un conjunto dinámico, otra opción, además de almacenar la cadena de selección, es crear un objeto con una SELpropiedad o ivar y almacenarlo.

@interface SelectorObject : NSObject
@property (assign, readonly, nonatomic) SEL selector;
- (id)initWithSelector:(SEL)selector;
@end

@implementation SelectorObject
- (id)initWithSelector:(SEL)selector {
  self = [super init];
  if (self) {
    _selector = selector;
  }
  return self;
}
@end

A continuación, también puede agregar un performmétodo a la clase e implementar la llamada al método allí.

big_m
fuente
1

Me gustaría complementar dos métodos para almacenar selectores en una matriz,

Primero, NSPointerArraypuede almacenar un puntero opaco, como SEL, como dijo Apple doc ,

NSPointerArray *selectors = [[NSPointerArray alloc] initWithOptions: NSPointerFunctionsOpaqueMemory];
[selectors addPointer:@selector(onSendButton:)];
[button addTarget: self action:[selectors pointerAt:0] forControlEvents:UIControlEventTouchUpInside];

En segundo lugar, la matriz de estilo C es mucho más simple,

SEL selectors[] = { @selector(onSendButton:) };
[button addTarget: self action:selectors[0] forControlEvents:UIControlEventTouchUpInside];

Elija cualquiera que desee.

DawnSong
fuente