¿Puede un bloque OBJ-C ejecutarse a sí mismo?
-
27-10-2019 - |
Pregunta
Esta es una extensión de este Queston:¿Es posible crear una categoría del objeto "bloque" en Objective-C?.
Básicamente, si bien parece posible crear una categoría en bloques, ya sea a través de NSObject o NSBlock, tengo problemas para comprender cómo el bloque podría evaluarse a sí mismo. El ejemplo dado en la respuesta a la última pregunta:
- (void) doFoo {
//do something awesome with self, a block
//however, you can't do "self()".
//You'll have to cast it to a block-type variable and use that
}
Implica que es posible lanzar de alguna manera a una variable de bloque, pero ¿cómo se ejecutaría el bloque en sí? Por ejemplo, digamos que hice una categoría en nsblock y en un método lo hice:
NSBlock* selfAsBlock = (NSBlock*)self;
¿Hay algún mensaje que pueda enviar a SelfAsblock para evaluar el bloque?
Solución
Implica que es posible lanzar de alguna manera a una variable de bloque
Como esto:
- (void)doFoo {
// Assume the block receives an int, returns an int,
// and cast self to the corresponding block type
int (^selfBlock)(int) = (int (^)(int))self;
// Call itself and print the return value
printf("in doFoo: %d\n", selfBlock(42));
}
Tenga en cuenta que (en la mayoría de los casos) debe corregir la firma de bloque para que el compilador pueda configurar el sitio de llamadas de acuerdo con la plataforma de destino ABI. En el ejemplo anterior, la firma es el tipo de retorno int
, parámetro único de tipo int
.
Un ejemplo completo es:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface Foo : NSObject
- (void)doFoo;
@end
@implementation Foo
- (void)doFoo {
// Assume the block receives an int, returns an int,
// and cast self to the corresponding block type
int (^selfBlock)(int) = (int (^)(int))self;
// Call itself and print the return value
printf("in doFoo: %d\n", selfBlock(42));
}
@end
int main(void) {
[NSAutoreleasePool new];
// From Dave's answer
Method m = class_getInstanceMethod([Foo class], @selector(doFoo));
IMP doFoo = method_getImplementation(m);
const char *type = method_getTypeEncoding(m);
Class nsblock = NSClassFromString(@"NSBlock");
class_addMethod(nsblock, @selector(doFoo), doFoo, type);
// A block that receives an int, returns an int
int (^doubler)(int) = ^int(int someNumber){ return someNumber + someNumber; };
// Call the category method which in turn calls itself (the block)
[doubler doFoo];
return 0;
}
Otros consejos
NSBlock
tiene un invoke
Método que se puede usar para llamar al bloque.
NSBlock* b = ^() { /* do stuff */ };
[b invoke];
Tenga en cuenta que este es un método privado e indocumentado.