Lista de sintaxis de declaración de bloque


277

La sintaxis de bloque en el Objetivo C (y de hecho C, supongo) es notoriamente incongruente. Pasar bloques como argumentos se ve diferente a declarar bloques como ivars, que se ven diferentes a typedeflos bloques ing.

¿Existe una lista completa de sintaxis de declaración de bloque que pueda tener a mano para una referencia rápida?


9
¿Qué tiene de malo "Declarar y crear bloques" en la Guía de temas de programación de bloques?
jscs

explicación directa del uso de propiedades de bloque: stackoverflow.com/a/20760583/294884
Fattie

Respuestas:


696

Lista de sintaxis de declaración de bloque

En todo momento, dejemos

  • return_typeser el tipo de objeto / primitivo / etc. te gustaría volver (comúnmente void)
  • blockName ser el nombre variable del bloque que estás creando
  • var_typeser el tipo objeto / primitivo / etc. desea pasar como argumento (déjelo en blanco sin parámetros)
  • varName ser el nombre de la variable del parámetro dado

Y recuerde que puede crear tantos parámetros como desee.

Bloques como variables

Posiblemente el más común para la declaración.

return_type (^blockName)(var_type) = ^return_type (var_type varName)
{
    // ...
};

Bloques como propiedades

Al igual que declarar bloques como variables, aunque sutilmente diferentes.

@property (copy) return_type (^blockName) (var_type);

Bloques como Parámetros

Tenga en cuenta que esto es distinto de "Bloques como argumentos"; en este caso, estás declarando un método que quiere un argumento de bloque.

- (void)yourMethod:(return_type (^)(var_type))blockName;

Bloques como argumentos

Tenga en cuenta que esto es distinto de "Bloques como parámetros"; en este caso, está llamando a un método que quiere un argumento de bloque con un bloque anónimo. Si ya ha declarado una variable de bloque, es suficiente pasar el nombre de la variable como argumento.

[someObject doSomethingWithBlock: ^return_type (var_type varName)
{
    //...
}];

Bloque anónimo

Funcionalmente es un bloque anónimo, sin embargo, la sintaxis para asignar bloques a variables es simplemente establecer la variable igual a un bloque anónimo.

^return_type (var_type varName)
{
    //...
};

typedef Bloquear

Esto le permite configurar un nombre corto al que se puede hacer referencia como cualquier otro nombre de clase durante la declaración de bloques.

typedef return_type (^blockName)(var_type);

Para luego utilizarlo en blockNamelugar de la sintaxis estándar de declaración de bloque, simplemente sustitúyalo.

Bloque en línea

Podría decirse que esta es una utilización menos útil de los bloques, pero no obstante puede tener su lugar. Un bloque en línea es un bloque anónimo llamado inmediatamente después de la creación de instancias.

^return_type (var_type varName)
{
    //...
}(var);

Los bloques en línea son principalmente útiles para la compensación de alcance, y son más o menos equivalentes a fragmentos simples de código delimitados por llaves.

{
   //...
}

Bloques recursivos

Esto le permite llamar a un bloque de sí mismo, creando un bucle que puede usarse durante devoluciones de llamada y llamadas GCD. Este método de creación de instancias está libre de ciclos de retención en ARC.

__block return_type (^blockName)(var_type) = [^return_type (var_type varName)
{
    if (returnCondition)
    {
        blockName = nil;
        return;
    }

    // ...
} copy];
blockName(varValue);

Bloques de retorno

Un método puede devolver un bloque,

- (return_type(^)(var_type))methodName
{
    // ...
}

como puede una función, aunque sea un poco extraño.

return_type (^FunctionName())(var_type)
{
    // ...
}

Addendums

Si me he perdido algo, hágamelo saber en los comentarios y lo investigaré / agregaré.

Ah, y en Swift ...

blockName = (varName: var_type) -> (return_type)

Es casi como si fuera una característica del lenguaje.


1
@pcperini ¡Una gran lista! ¿Y cómo usar la definición de bloque typedef'd en la declaración de variable (primer elemento de su lista)? Lógico BlockType ^blockVar = Anonymous Blockmuestra error de sintaxis, sin ^ también :(
esp

14
De alguna manera, mi cerebro es incapaz de recordar todas estas diversas sintaxis para las declaraciones de bloque. Probablemente mire esta respuesta una vez por semana. Ojalá pudiera darte 10 votos a favor por esto.
Ben Baron

36
Necesitamos un Salón de la fama de StackOverflow para respuestas como esta.
bejonbee

1
He convertido esto en Markdown para usarlo con un visor para imprimir. ¡Práctico! gist.github.com/swizzlr/6268955
Swizzlr

20
Creo que necesito esto como un tatuaje.
Isaac Overacker


39

Typedef:

typedef void (^block)(NSString *arg);

En línea:

void (^block)(NSString *) = ^(NSString *param) {
  // do something....
};

Método:

- (void)method:(void (^)(NSString *param))handler

Esta respuesta muestra que no es tan complicado después de todo ... solo 3 sintaxis diferentes para mezclar y combinar.
Joseph Chen

44
La respuesta aceptada es solo una copia de esta respuesta con hinchazón innecesaria.
Erik Aigner

16

La biblioteca de fragmentos Xcode 4 contiene plantillas para los tipos de bloques y los bloques en línea como variables. También están disponibles mediante autocompletado ( typedefblocky inlineblock).

Para bloques como argumentos de métodos, recomendaría declarar ay typedefluego simplemente usar eso. Hace que el código sea mucho más fácil de leer.


11

Escribí un Bloque de finalización para una clase que devolverá los valores de un dado después de haberlos sacudido:

  1. Definir typedef con returnType ( declaración .hanterior @interface)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
  2. Definir a @propertypara el bloque ( .h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
  3. Definir un método con finishBlock( .h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
  4. Insertar método definido previa en .mel archivo y se comprometan finishBlocka @propertydefinir antes

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
  5. Para activar el completionBlockpaso variableType predefinido (no olvide comprobar si completionBlockexiste)

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }

7
typedef void (^OkBtnBlock)(id data);
typedef void (^CancelBtnBlock)();

@property (nonatomic, strong) OkBtnBlock okBtnBlock;
@property (nonatomic, strong) CancelBtnBlock cancelBtnBlock;

+ (void)foo:(OkBtnBlock)okBtn andCancel:(CancelBtnBlock)btnCancel;

Sería bueno describir todo el proceso paso a paso, los bloques son difíciles de entender si eres nuevo en iOS ...
Alex Cio

3

Si necesita volver a trabajar en Xcode 4.2, también puede @ sintetizar un bloque declarado como una propiedad tal como lo haría con una propiedad que no sea de bloque. No dejes que la sintaxis de bloque te arroje.

Si su propiedad de bloque es esta:

@property (copy) return_type (^blockName) (var_type);

Entonces tu @synthesize es este:

@property blockName;

Salud.


Hola, ¿podrías volver a comprobarlo? Solo intentaba seguirte. @property blockNameNo funciona. Creo que debería ser @synthesize blockName;? (para sintetizar un bloque)
jeet.chanchawat

oops ... espera ya (indirectamente) mencionó que no funcionará con xcode 7.
jeet.chanchawat
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.