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?

¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top