¿Por qué NULL necesita tipeo con bloques?

Vea este escenario:

@property (nonatomic,copy) UIImage * (^bgImageBlock)(void); 

Definición de la variable de bloque bgImageBlock :

 objDrawing.bgImageBlock = ^(){ return (UIImage *)NULL; }; 

bgImageBlock tiene el tipo de retorno UIImage que si paso NULL así:

 objDrawing.bgImageBlock = ^(){ return NULL; }; 

Daría error en el time de compilation: Incompitable block pointer type assigning to UIImage.

Mientras que si tomo la variable simple UIImage y la asigno NULL, está absolutamente bien. Entonces, ¿por qué en el caso de los bloques? No puede aceptar NULL sin tipeo. ?

El comstackdor infiere el tipo de retorno de bloque del tipo de object que devuelve, si no lo explica explícitamente. Entonces, en este caso:

 objDrawing.bgImageBlock = ^(){ return NULL; }; 

… Supongo que está viendo el NULL e infiriendo que el tipo de retorno de su bloque es void * , el tipo de NULL . Esto no coincide con el tipo de propiedad, por lo que el comstackdor se queja. (Tenga en count que el error es sobre el "tipo de puntero de bloque", es un desajuste entre la statement de su propiedad de bloque y el bloque que intenta almacenar en él).

Si explícitamente le diga su tipo, debería poder usar su retorno NULL simple:

 objDrawing.bgImageBlock = ^UIImage*(){ return NULL; }; 

Que el tipo de bloque se infiere del tipo de devolución se documenta en la documentation de Clang :

El tipo de devolución es opcional y se infiere de las declaraciones de devolución. Si las declaraciones de devolución devuelven un valor, todos deben devolver un valor del mismo tipo. Si no se devuelve ningún valor, el tipo inferido del bloque es nulo; de lo contrario, es el tipo del valor de la statement de devolución.

Esta inferencia del tipo de retorno y el hecho de que el comstackdor verifica los types de puntero para usted y produce el error que está recibiendo si hay un desajuste, se menciona en la session de WWDC 2013 "Avances en Objective-C". (Ver la parte titulada "Inferencia de tipo de retorno").

Tu bloque está esperando el tipo UIImage* . Sin embargo, siendo NULL un puntero, simplemente no reconoce que apunte a cualquier parte del tipo UIImage* (ya sea nada). Bam, error

Sin embargo, ahora está lanzando un puntero. En realidad no hace nada en time de ejecución. Simplemente modifica el tipo apuntado , que luego afecta las operaciones subsiguientes en el valor resultante. Pero el valor del puntero real seguirá siendo el mismo a través del yeso.

Mientras el puntero real sigue siendo el mismo (sin embargo, el valor que se señala no es nada), ahora apunta a un tipo que se espera que el bloque regrese. Todo está bien. 🙂

NULL es del tipo void * , por lo que se infiere que el bloque tiene un tipo de retorno void * , y los types de puntero que no son Objective-C (como void * ) no son compatibles con los types de puntero Objective-C (como UIImage * ) . En su lugar, debe usar nil , que también es un puntero nulo, pero de tipo id , que es compatible con todos los types de puntero Objective-C.