iOS bloquea la introspección
objective-c block (2)
Me gustaría saber dos cosas:
1- ¿Es posible utilizando la introspección de object-c para saber el tipo de retorno de un bloque?
Por ejemplo: int (^CountBlock)(NSArray *array)
Me gustaría saber si el tipo que devolverá es int
.
La segunda pregunta es:
2- ¿Puedo mantener una referencia a un bloque genérico? Lo que quiero decir con esto es que básicamente puedo hacer algo como id myBlock
y con esta respuesta la primera pregunta.
Lo que intenté
Este tipo de cosas no es posible:
id aBlock = ^{
NSString * aString = @"OMG";
return aString;
};
aBlock();
Como el compilador ve que el id aBlock
no es una función o un puntero de función.
1) Esta respuesta habla de cómo agarrar la firma de un bloque. Aquí está el código relevante:
static const char *BlockSig(id blockObj)
{
struct Block *block = (void *)blockObj;
struct BlockDescriptor *descriptor = block->descriptor;
int copyDisposeFlag = 1 << 25;
int signatureFlag = 1 << 30;
assert(block->flags & signatureFlag);
int index = 0;
if(block->flags & copyDisposeFlag)
index += 2;
return descriptor->rest[index];
}
Realmente no es lo ideal, ya que solo obtienes la cadena @encode
de la firma, que se ve así: @"i16@?0@8"
. Me encantaría ver si alguien tiene un mejor enfoque.
2) Definitivamente puedes lanzar bloques ay desde tipo id
:
typedef void(^MyBlockType)(void);
id aBlock = ^ { };
((MyBlockType)aBlock)();
Por supuesto, si convierte al tipo de bloque incorrecto, terminará con un comportamiento indefinido.
Creo que el problema para el número 2 es que los bloques se nombran como parte de la definición de tipo, por ejemplo,
void (^blockName)(void) = ^{};
Una solución es definir un tipo de bloque genérico:
typedef void(^BlockType)(void);
BlockType myBlock = ^{};
myBlock();
edición: señalada por @neilco, una forma mucho más sencilla de usar tipos de bloques de envío (que no devuelven nada y no aceptan argumentos):
dispatch_block_t myBlock = ^{};
myBlock();