Bem, porque seria muito útil. Eu não precisaria saber o que é, desde que eu tenha a sintaxe correta e se comporte como um NSObject.
gurghet
5
Se você não sabe o que é, como você sabe que seria muito útil?
Stephen Canon
5
Você não deve usá-los se você não sabe o que eles são :)
Richard J. Ross III
5
@ Moshe, aqui estão algumas razões que vêm à mente. Os blocos são mais fáceis de implementar do que uma classe delegada completa, os blocos são leves e você tem acesso a variáveis que estão no contexto desse bloco. Os retornos de chamada de eventos podem ser feitos efetivamente usando blocos (o cocos2d os utiliza quase que exclusivamente).
Richard J. Ross III
2
Não está completamente relacionado, mas como alguns dos comentários se queixam da sintaxe de bloco "feia", aqui está um ótimo artigo que deriva a sintaxe dos primeiros princípios: nilsou.com/blog/2013/08/08/21/objective-c-blocks-syntax
Com o xCode 4.4 ou mais recente, você não precisa sintetizar. Isso tornará ainda mais conciso. Apple Doc
Eric
uau, eu não sabia disso, obrigado! ... Embora eu muitas vezes fazem@synthesize myProp = _myProp
Robert
7
@Robert: Você está com sorte novamente, porque sem colocar @synthesizeo padrão é o que você está fazendo @synthesize name = _name;stackoverflow.com/a/12119360/1052616
Eric
1
@CharlieMonroe - Sim, você provavelmente está certo, mas não precisa de uma implementação desalocada para nada ou liberar a propriedade do bloco sem o ARC? (sua sido um tempo desde que eu usei não-ARC)
Robert
1
@ imcaptor: Sim, pode causar vazamento de memória caso você não a libere em desalocação - assim como qualquer outra variável.
Charlie Monroe
210
Aqui está um exemplo de como você realizaria essa tarefa:
#import <Foundation/Foundation.h>typedefint(^IntBlock)();@interface myobj :NSObject{IntBlock compare;}@property(readwrite, copy)IntBlock compare;@end@implementation myobj
@synthesize compare;-(void)dealloc
{// need to release the block since the property was declared copy. (for heap// allocated blocks this prevents a potential leak, for compiler-optimized // stack blocks it is a no-op)// Note that for ARC, this is unnecessary, as with all properties, the memory management is handled for you.[compare release];[super dealloc];}@endint main (){@autoreleasepool{
myobj *ob =[[myobj alloc] init];
ob.compare =^{return rand();};NSLog(@"%i", ob.compare());// if not ARC[ob release];}return0;}
Agora, a única coisa que precisaria ser alterada se você precisasse alterar o tipo de comparação seria o typedef int (^IntBlock)(). Se você precisar passar dois objetos para ele, mude para:: typedef int (^IntBlock)(id, id)e altere seu bloco para:
^(id obj1, id obj2){return rand();};
Eu espero que isso ajude.
EDIT 12 de março de 2012:
Para o ARC, não são necessárias alterações específicas, pois o ARC gerenciará os blocos para você, desde que sejam definidos como cópia. Também não é necessário definir a propriedade nula no seu destruidor.
// Here is a block as a property://// Someone passes you a block. You "hold on to it",// while you do other stuff. Later, you use the block.//// The property 'doStuff' will hold the incoming block.@property(copy)void(^doStuff)(void);// Here's a method in your class.// When someone CALLS this method, they PASS IN a block of code,// which they want to be performed after the method is finished.-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater;// We will hold on to that block of code in "doStuff".
Aqui está o seu arquivo .m:
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater
{// Regarding the incoming block of code, save it for later:
self.doStuff = pleaseDoMeLater;// Now do other processing, which could follow various paths,// involve delays, and so on. Then after everything:[self _alldone];}-(void)_alldone
{NSLog(@"Processing finished, running the completion block.");// Here's how to run the block:if( self.doStuff != nil )
self.doStuff();}
Cuidado com o código de exemplo desatualizado.
Com sistemas modernos (2014 ou superior), faça o que é mostrado aqui. É simples assim.
Talvez você deva também dizer que agora (2016) está tudo bem em strongvez de usar copy?
Nik Kov
Você pode explicar por que a propriedade não deve ser nonatomicdiferente das práticas recomendadas para a maioria dos outros casos usando propriedades?
Por uma questão de posteridade / completude… Aqui estão dois exemplos COMPLETOS de como implementar essa "maneira de fazer as coisas" ridiculamente versátil. A resposta de Robert é alegremente concisa e correta, mas aqui também quero mostrar maneiras de realmente "definir" os blocos.
@interfaceReusableClass:NSObject@property(nonatomic,copy)CALayer*(^layerFromArray)(NSArray*);@end@implementationResusableClassstaticNSStringconst* privateScope =@"Touch my monkey.";-(CALayer*(^)(NSArray*)) layerFromArray {return^CALayer*(NSArray*array){CALayer*returnLayer =CALayer.layer
for(id thing in array){[returnLayer doSomethingCrazy];[returnLayer setValue:privateScope
forKey:@"anticsAndShenanigans"];}returnlist;};}@end
Boba? Sim. Útil?Infernos, sim. Aqui está uma maneira diferente e "mais atômica" de definir a propriedade ... e uma classe que é ridiculamente útil…
Isso ilustra a configuração da propriedade do bloco por meio do acessador (embora dentro de init, uma prática discutivelmente arriscada ..) versus o mecanismo "não-atômico" "getter" do primeiro exemplo. Em ambos os casos ... as implementações "codificadas" sempre podem ser substituídas, por exemplo .. a lá ..
Além disso ... se você deseja adicionar uma propriedade de bloco em uma categoria ... diga que deseja usar um bloco em vez de uma ação / ação antiga de ação / ação ... Você pode apenas usar valores associados para, bem .. associe os blocos.
typedefvoid(^NSControlActionBlock)(NSControl*);@interfaceNSControl(ActionBlocks)@property(copy)NSControlActionBlock actionBlock;@end@implementationNSControl(ActionBlocks)-(NSControlActionBlock) actionBlock {// use the "getter" method's selector to store/retrieve the block!return objc_getAssociatedObject(self, _cmd);}-(void) setActionBlock:(NSControlActionBlock)ab {
objc_setAssociatedObject(// save (copy) the block associatively, as categories can't synthesize Ivars.
self,@selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
self.target = self;// set self as target (where you call the block)
self.action =@selector(doItYourself);// this is where it's called.}-(void) doItYourself {if(self.actionBlock && self.target == self) self.actionBlock(self);}@end
Agora, quando você aperta um botão, não precisa criar um IBActiondrama. Basta associar o trabalho a ser feito na criação ...
Esse padrão pode ser aplicado OVER e OVER às APIs do cacau. Usar propriedades para trazer as partes relevantes do seu código mais juntos , eliminar paradigmas delegação complicadas , e alavancar o poder de objetos além do que apenas agindo como "recipientes" mudos.
Alex, ótimo exemplo associado. Você sabe, eu estou pensando sobre o não atômico. Pensamentos?
Gordo
2
É muito raro que "atômico" seja a coisa certa a fazer para uma propriedade. Seria muito estranho definir uma propriedade de bloco em um segmento e lê-lo em outro segmento ao mesmo tempo , ou definir a propriedade do bloco simultaneamente a partir de vários segmentos. Portanto, o custo de "atômico" vs. "não atômico" não oferece vantagens reais.
gnasher729
8
Claro que você pode usar blocos como propriedades. Mas verifique se eles são declarados como @property (cópia) . Por exemplo:
No MRC, os blocos que capturam variáveis de contexto são alocados na pilha ; eles serão liberados quando o quadro da pilha for destruído. Se eles forem copiados, um novo bloco será alocado no heap , que poderá ser executado posteriormente depois que o quadro da pilha for exibido.
Isso não pretende ser "a boa resposta", pois esta pergunta solicita explicitamente o ObjectiveC. Quando a Apple introduziu o Swift na WWDC14, eu gostaria de compartilhar as diferentes maneiras de usar blocos (ou fechamentos) no Swift.
Olá, Swift
Você tem várias maneiras oferecidas para passar um bloco equivalente à função no Swift.
Eu encontrei três.
Para entender isso, sugiro que você teste no playground esse pequeno pedaço de código.
func test(function:String->String)->String{return function("test")}
func funcStyle(s:String)->String{return"FUNC__"+ s +"__FUNC"}
let resultFunc = test(funcStyle)
let blockStyle:(String)->String={s in return"BLOCK__"+ s +"__BLOCK"}
let resultBlock = test(blockStyle)
let resultAnon = test({(s:String)->String in return"ANON_"+ s +"__ANON"})
println(resultFunc)
println(resultBlock)
println(resultAnon)
Rápido, otimizado para fechamentos
Como o Swift é otimizado para desenvolvimento assíncrono, a Apple trabalhou mais em fechamentos. A primeira é que a assinatura da função pode ser inferida para que você não precise reescrevê-la.
Acessar parâmetros por números
let resultShortAnon = test({return"ANON_"+ $0 +"__ANON"})
Inferência de parâmetros com nomeação
let resultShortAnon2 = test({myParam in return"ANON_"+ myParam +"__ANON"})
Trailing Closure
Esse caso especial funciona apenas se o bloco for o último argumento, chamado de fechamento final
Aqui está um exemplo (mesclado com assinatura inferida para mostrar o poder do Swift)
let resultTrailingClosure = test {return"TRAILCLOS_"+ $0 +"__TRAILCLOS"}
Finalmente:
Usando todo esse poder, o que eu faria é misturar o fechamento à direita e a inferência de tipo (com nomeação para facilitar a leitura)
PFFacebookUtils.logInWithPermissions(permissions){
user, error in
if(!user){
println("Uh oh. The user cancelled the Facebook login.")}elseif(user.isNew){
println("User signed up and logged in through Facebook!")}else{
println("User logged in through Facebook!")}}
func test(function:String->String, param1:String, param2:String)->String{return function("test"+param1 + param2)}
func funcStyle(s:String)->String{return"FUNC__"+ s +"__FUNC"}
let resultFunc = test(funcStyle,"parameter 1","parameter 2")
let blockStyle:(String)->String={s in return"BLOCK__"+ s +"__BLOCK"}
let resultBlock = test(blockStyle,"parameter 1","parameter 2")
let resultAnon = test({(s:String)->String in return"ANON_"+ s +"__ANON"},"parameter 1","parameter 2")
println(resultFunc)
println(resultBlock)
println(resultAnon)
Respostas:
Se você repetir o mesmo bloco em vários lugares, use um tipo def
fonte
@synthesize myProp = _myProp
@synthesize
o padrão é o que você está fazendo@synthesize name = _name;
stackoverflow.com/a/12119360/1052616Aqui está um exemplo de como você realizaria essa tarefa:
Agora, a única coisa que precisaria ser alterada se você precisasse alterar o tipo de comparação seria o
typedef int (^IntBlock)()
. Se você precisar passar dois objetos para ele, mude para::typedef int (^IntBlock)(id, id)
e altere seu bloco para:Eu espero que isso ajude.
EDIT 12 de março de 2012:
Para o ARC, não são necessárias alterações específicas, pois o ARC gerenciará os blocos para você, desde que sejam definidos como cópia. Também não é necessário definir a propriedade nula no seu destruidor.
Para mais informações, consulte este documento: http://clang.llvm.org/docs/AutomaticReferenceCounting.html
fonte
Para Swift, basta usar fechamentos: exemplo.
No Objetivo-C:
@property (cópia) void
É simples assim.
Aqui está a documentação real da Apple, que indica exatamente o que usar:
Doco da Apple.
No seu arquivo .h:
Aqui está o seu arquivo .m:
Cuidado com o código de exemplo desatualizado.
Com sistemas modernos (2014 ou superior), faça o que é mostrado aqui. É simples assim.
fonte
strong
vez de usarcopy
?nonatomic
diferente das práticas recomendadas para a maioria dos outros casos usando propriedades?Por uma questão de posteridade / completude… Aqui estão dois exemplos COMPLETOS de como implementar essa "maneira de fazer as coisas" ridiculamente versátil. A resposta de Robert é alegremente concisa e correta, mas aqui também quero mostrar maneiras de realmente "definir" os blocos.
Boba? Sim. Útil?Infernos, sim. Aqui está uma maneira diferente e "mais atômica" de definir a propriedade ... e uma classe que é ridiculamente útil…
Isso ilustra a configuração da propriedade do bloco por meio do acessador (embora dentro de init, uma prática discutivelmente arriscada ..) versus o mecanismo "não-atômico" "getter" do primeiro exemplo. Em ambos os casos ... as implementações "codificadas" sempre podem ser substituídas, por exemplo .. a lá ..
Além disso ... se você deseja adicionar uma propriedade de bloco em uma categoria ... diga que deseja usar um bloco em vez de uma ação / ação antiga de ação / ação ... Você pode apenas usar valores associados para, bem .. associe os blocos.
Agora, quando você aperta um botão, não precisa criar um
IBAction
drama. Basta associar o trabalho a ser feito na criação ...Esse padrão pode ser aplicado OVER e OVER às APIs do cacau. Usar propriedades para trazer as partes relevantes do seu código mais juntos , eliminar paradigmas delegação complicadas , e alavancar o poder de objetos além do que apenas agindo como "recipientes" mudos.
fonte
Claro que você pode usar blocos como propriedades. Mas verifique se eles são declarados como @property (cópia) . Por exemplo:
No MRC, os blocos que capturam variáveis de contexto são alocados na pilha ; eles serão liberados quando o quadro da pilha for destruído. Se eles forem copiados, um novo bloco será alocado no heap , que poderá ser executado posteriormente depois que o quadro da pilha for exibido.
fonte
Disclamer
Isso não pretende ser "a boa resposta", pois esta pergunta solicita explicitamente o ObjectiveC. Quando a Apple introduziu o Swift na WWDC14, eu gostaria de compartilhar as diferentes maneiras de usar blocos (ou fechamentos) no Swift.
Olá, Swift
Você tem várias maneiras oferecidas para passar um bloco equivalente à função no Swift.
Eu encontrei três.
Para entender isso, sugiro que você teste no playground esse pequeno pedaço de código.
Rápido, otimizado para fechamentos
Como o Swift é otimizado para desenvolvimento assíncrono, a Apple trabalhou mais em fechamentos. A primeira é que a assinatura da função pode ser inferida para que você não precise reescrevê-la.
Acessar parâmetros por números
Inferência de parâmetros com nomeação
Trailing Closure
Esse caso especial funciona apenas se o bloco for o último argumento, chamado de fechamento final
Aqui está um exemplo (mesclado com assinatura inferida para mostrar o poder do Swift)
Finalmente:
Usando todo esse poder, o que eu faria é misturar o fechamento à direita e a inferência de tipo (com nomeação para facilitar a leitura)
fonte
Olá, Swift
Complementando o que @Francescu respondeu.
Adicionando parâmetros extras:
fonte
Você pode seguir o formato abaixo e pode usar a
testingObjectiveCBlock
propriedade na classePara mais informações, dê uma olhada aqui
fonte