Lista de sintaxe da declaração de bloco

277

A sintaxe do bloco no Objetivo C (e de fato C, presumo) é notoriamente incongruente. Passar blocos como argumentos parece diferente de declarar blocos como ivars, que parece diferente de um typedefbloco.

Existe uma lista abrangente de sintaxe de declaração de bloco que eu poderia manter à mão para referência rápida?

Patrick Perini
fonte
9
O que há de errado com "Declarando e criando blocos" no Guia de tópicos de programação de blocos?
JSCs
explicação simples de usar propriedades do bloco: stackoverflow.com/a/20760583/294884
Fattie

Respostas:

696

Lista de sintaxes de declaração de bloco

Ao longo, vamos

  • return_typeseja o tipo de objeto / primitivo / etc. você gostaria de retornar (normalmente void)
  • blockName seja o nome da variável do bloco que você está criando
  • var_typeseja o tipo objeto / primitivo / etc. você gostaria de passar como argumento (deixe em branco sem parâmetros)
  • varName ser o nome da variável do parâmetro especificado

E lembre-se de que você pode criar quantos parâmetros desejar.

Blocos como Variáveis

Possivelmente o mais comum para a declaração.

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

Blocos como propriedades

É como declarar blocos como variáveis, por mais sutil que sejam.

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

Blocos como parâmetros

Observe que isso é diferente de "Blocos como argumentos"; Nesse caso, você está declarando um método que deseja um argumento de bloco.

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

Blocos como argumentos

Observe que isso é diferente de "Blocos como parâmetros"; Nesse caso, você está chamando um método que deseja um argumento de bloco com um bloco anônimo. Se você já declarou uma variável de bloco, é suficiente passar o nome da variável como argumento.

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

Bloco anônimo

Este é funcionalmente um bloco anônimo, no entanto, a sintaxe para atribuir blocos a variáveis ​​é simplesmente definir a variável igual a um bloco anônimo.

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

typedef Quadra

Isso permite que você configure um nome abreviado que possa ser referenciado como qualquer outro nome de classe durante a declaração de blocos.

typedef return_type (^blockName)(var_type);

Para usar posteriormente, em blockNamevez da sintaxe da declaração de bloco padrão, basta substituir.

Bloco embutido

É indiscutivelmente uma utilização menos útil dos blocos, mas ainda assim pode ter seu lugar. Um bloco embutido é um bloco anônimo chamado imediatamente após a instanciação.

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

Os blocos embutidos são úteis principalmente para a compensação do escopo e são aproximadamente equivalentes a simples pedaços de código delimitados por colchetes.

{
   //...
}

Blocos Recursivos

Isso permite que você chame um bloco de si mesmo, criando um loop que pode ser usado durante retornos de chamada e chamadas GCD. Esse método de instanciação está livre de ciclos de retenção no ARC.

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

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

Blocos de retorno

Um método pode retornar um bloco,

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

como pode uma função, se um pouco estranha.

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

Adendos

Se eu perdi alguma coisa, informe-me nos comentários e eu os pesquisarei / os adicionarei.

Ah, e em Swift ...

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

É quase como se fosse um recurso de idioma.

Patrick Perini
fonte
1
@pcperini Uma ótima lista! E como usar a definição de bloco typedef'd na declaração da variável (1º item da sua lista)? Lógico BlockType ^blockVar = Anonymous Blockmostra erro de sintaxe, sem ^ também :(
esp
14
De alguma forma, meu cérebro é incapaz de lembrar todas essas várias sintaxes para declarações de bloco. Eu provavelmente olho para esta resposta uma vez por semana. Gostaria de poder lhe dar 10 votos positivos por isso.
Ben Baron
36
Precisamos de um Hall da fama do StackOverflow para respostas como essa.
bejonbee
1
Eu converti isso no Markdown para uso com um visualizador para impressão. Handy! gist.github.com/swizzlr/6268955
Swizzlr
20
Eu acho que preciso disso como uma tatuagem.
Isaac Overacker
83

Pessoalmente, gosto de usar este site ( http://fuckingblocksyntax.com ). O nome é mais fácil de lembrar do que a própria sintaxe do bloco:

http://fuckingblocksyntax.com

e se você não puder carregar URLs com palavrões, poderá usar este espelho: http://goshdarnblocksyntax.com

site do fuckingblocksyntax

psy
fonte
1
nome perfeito para o site ..: D
Vineeth 2/16
39

Typedef:

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

Na linha:

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

Método:

- (void)method:(void (^)(NSString *param))handler
Erik Aigner
fonte
Esta resposta mostra que não é tão complicado, afinal ... apenas 3 sintaxes diferentes para misturar e combinar.
Joseph Chen
4
A resposta aceita é apenas uma cópia desta resposta com inchaço desnecessário.
Erik Aigner
16

A biblioteca de trechos do Xcode 4 contém modelos para typedefs de bloco e blocos embutidos como variáveis. Eles também estão disponíveis através do preenchimento automático ( typedefblocke inlineblock).

Para blocos como argumentos para métodos, eu recomendaria declarar um typedefe simplesmente usá-lo. Isso torna o código muito mais fácil de ler.

omz
fonte
11

Escrevi um completeBlock para uma classe que retornará os valores de um dado depois que ele foi sacudido:

  1. Defina typedef com returnType ( declaração .hacima @interface)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
  2. Defina a @propertypara o bloco ( .h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
  3. Defina um método com finishBlock( .h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
  4. Insira o método definido anterior no .marquivo e confirme finishBlockcom o @propertydefinido antes

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
  5. Para acionar a completionBlockpassagem de typeType predefinido (não se esqueça de verificar se completionBlockexiste)

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }
Alex Cio
fonte
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;
benhi
fonte
Seria bom para descrever todo o processo passo a passo, os blocos são difíceis de entender se você é novo para ios ...
Alex Cio
3

Se você precisar trabalhar no Xcode 4.2, também pode @ sintetizar um bloco declarado como uma propriedade, exatamente como faria com uma propriedade que não seja de bloco. Não deixe que a sintaxe do bloco o atinja.

Se a sua propriedade de bloco for esta:

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

Então o seu @synthesize é o seguinte:

@property blockName;

Felicidades.

Alex Zavatone
fonte
Oi, você poderia voltar a verificar .. Eu só estava tentando segui-lo .. @property blockNamenão está funcionando. Eu acho que deveria ser @synthesize blockName;? (para a síntese de um bloco)
jeet.chanchawat
oops ... esperar você já (indiretamente) mencionou que ele vai trabalhar com o Xcode 7.
jeet.chanchawat