Bueno, porque sería muy útil. No necesitaría saber qué es mientras tenga la sintaxis correcta y se comporte como un NSObject.
gurghet
55
Si no sabes qué es, ¿cómo sabes que sería muy útil?
Stephen Canon
55
No deberías usarlos si no sabes cuáles son :)
Richard J. Ross III
55
@Moshe aquí hay algunas razones que me vienen a la mente. Los bloques son más fáciles de implementar que una clase de delegado completo, los bloques son livianos y usted tiene acceso a las variables que están en el contexto de ese bloque. Las devoluciones de llamada de eventos se pueden hacer de manera efectiva utilizando bloques (cocos2d los usa casi exclusivamente).
Richard J. Ross III
2
No está completamente relacionado, pero como algunos de los comentarios se quejan de la sintaxis de bloques "feos", aquí hay un gran artículo que deriva la sintaxis de los primeros principios: nilsou.com/blog/2013/08/21/objective-c-blocks-syntax
Con xCode 4.4 o más reciente no necesita sintetizar. Eso lo hará aún más conciso. Apple Doc
Eric
wow, no lo sabía, gracias! ... Aunque a menudo lo hago@synthesize myProp = _myProp
Robert
77
@Robert: Estás de suerte otra vez, porque sin poner @synthesizeel valor predeterminado es lo que estás haciendo @synthesize name = _name;stackoverflow.com/a/12119360/1052616
Eric
1
@CharlieMonroe: Sí, probablemente tenga razón, pero ¿no necesita una implementación de Dealloc para anular o liberar la propiedad de bloque sin ARC? (ha pasado un tiempo desde que usé no ARC)
Robert
1
@imcaptor: Sí, puede causar pérdidas de memoria en caso de que no lo libere en dealloc, al igual que con cualquier otra variable.
Charlie Monroe
210
Aquí hay un ejemplo de cómo lograría tal tarea:
#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;}
Ahora, lo único que necesitaría cambiar si necesita cambiar el tipo de comparación sería el typedef int (^IntBlock)(). Si necesita pasarle dos objetos, cámbielo a esto: typedef int (^IntBlock)(id, id)y cambie su bloque a:
^(id obj1, id obj2){return rand();};
Espero que esto ayude.
EDITAR 12 de marzo de 2012:
Para ARC, no se requieren cambios específicos, ya que ARC administrará los bloques por usted siempre que estén definidos como copia. Tampoco es necesario que establezca la propiedad en nulo en su destructor.
// 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".
Aquí está su archivo .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();}
Tenga cuidado con el código de ejemplo desactualizado.
Con los sistemas modernos (2014+), haga lo que se muestra aquí. Es así de simple.
Tal vez también debería decir que ahora (2016) está bien usar en stronglugar de copy?
Nik Kov
¿Puede explicar por qué la propiedad no debería ser nonatomicdiferente de las mejores prácticas para la mayoría de los otros casos que usan propiedades?
Por el bien de la posteridad / integridad ... Aquí hay dos ejemplos COMPLETOS de cómo implementar esta "forma de hacer las cosas" ridículamente versátil. La respuesta de @ Robert es maravillosamente concisa y correcta, pero aquí también quiero mostrar formas de "definir" realmente los bloques.
@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
¿Tonto? Si. ¿Útil? Genial. Aquí hay una forma diferente y "más atómica" de establecer la propiedad ... y una clase que es ridículamente útil ...
Esto ilustra la configuración de la propiedad de bloque a través del descriptor de acceso (aunque dentro de init, una práctica discutiblemente discutible ...) frente al mecanismo "getter" "no atómico" del primer ejemplo. En cualquier caso ... las implementaciones "codificadas" siempre se pueden sobrescribir, por ejemplo ... a lá ..
Además ... si desea agregar una propiedad de bloque en una categoría ... digamos que desea usar un Bloque en lugar de alguna "acción" de objetivo / acción de la vieja escuela ... Puede usar los valores asociados para, bueno ... asocia los bloques.
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
Ahora, cuando haces un botón, no tienes que configurar un IBActiondrama ... Solo asocia el trabajo a realizar en la creación ...
Este patrón puede aplicarse OVER y OVER a las API de Cocoa. Usar las propiedades de traer las partes pertinentes de su código más juntos , eliminar los paradigmas delegación contorneados , y aprovechar el poder de los objetos más allá de simplemente actuar como "contenedores" mudos.
Alex, gran ejemplo asociado. Sabes, me pregunto sobre lo no atómico. Pensamientos?
Fattie
2
Es muy raro que "atómico" sea lo correcto para una propiedad. Sería muy extraño establecer una propiedad de bloque en un subproceso y leerla en otro subproceso al mismo tiempo , o establecer la propiedad de bloque simultáneamente desde múltiples subprocesos. Por lo tanto, el costo de "atómico" versus "no atómico" no le ofrece ninguna ventaja real.
gnasher729
8
Por supuesto, podría usar bloques como propiedades. Pero asegúrese de que se declaren como @property (copia) . Por ejemplo:
En MRC, los bloques que capturan variables de contexto se asignan en la pila ; se liberarán cuando se destruya el marco de la pila. Si se copian, se asignará un nuevo bloque en el montón , que se puede ejecutar más tarde después de que se apunte el marco de la pila.
Esto no pretende ser "la buena respuesta", ya que esta pregunta solicita explícitamente ObjectiveC. Cuando Apple presentó Swift en la WWDC14, me gustaría compartir las diferentes formas de usar bloque (o cierres) en Swift.
Hola swift
Tiene muchas formas de pasar un bloque equivalente a la función en Swift.
Encontré tres.
Para entender esto, le sugiero que pruebe en el patio este pequeño 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, optimizado para cierres
Como Swift está optimizado para el desarrollo asincrónico, Apple trabajó más en los cierres. La primera es que la firma de la función se puede inferir para que no tenga que volver a escribirla.
Acceda a los parámetros por números
let resultShortAnon = test({return"ANON_"+ $0 +"__ANON"})
Inferencia de parámetros con nomenclatura
let resultShortAnon2 = test({myParam in return"ANON_"+ myParam +"__ANON"})
Cierre final
Este caso especial solo funciona si el bloque es el último argumento, se llama cierre final
Aquí hay un ejemplo (combinado con la firma inferida para mostrar el poder de Swift)
let resultTrailingClosure = test {return"TRAILCLOS_"+ $0 +"__TRAILCLOS"}
Finalmente:
Usar todo este poder lo que haría es mezclar el cierre final y la inferencia de tipos (con nombres para facilitar la lectura)
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)
Respuestas:
Si va a repetir el mismo bloque en varios lugares, use un tipo def
fuente
@synthesize myProp = _myProp
@synthesize
el valor predeterminado es lo que estás haciendo@synthesize name = _name;
stackoverflow.com/a/12119360/1052616Aquí hay un ejemplo de cómo lograría tal tarea:
Ahora, lo único que necesitaría cambiar si necesita cambiar el tipo de comparación sería el
typedef int (^IntBlock)()
. Si necesita pasarle dos objetos, cámbielo a esto:typedef int (^IntBlock)(id, id)
y cambie su bloque a:Espero que esto ayude.
EDITAR 12 de marzo de 2012:
Para ARC, no se requieren cambios específicos, ya que ARC administrará los bloques por usted siempre que estén definidos como copia. Tampoco es necesario que establezca la propiedad en nulo en su destructor.
Para obtener más información, consulte este documento: http://clang.llvm.org/docs/AutomaticReferenceCounting.html
fuente
Para Swift, solo use cierres: ejemplo.
En el objetivo-C:
@property (copy) void
Es así de simple.
Aquí está la documentación real de Apple, que establece exactamente qué usar:
Apple doco.
En su archivo .h:
Aquí está su archivo .m:
Tenga cuidado con el código de ejemplo desactualizado.
Con los sistemas modernos (2014+), haga lo que se muestra aquí. Es así de simple.
fuente
strong
lugar decopy
?nonatomic
diferente de las mejores prácticas para la mayoría de los otros casos que usan propiedades?Por el bien de la posteridad / integridad ... Aquí hay dos ejemplos COMPLETOS de cómo implementar esta "forma de hacer las cosas" ridículamente versátil. La respuesta de @ Robert es maravillosamente concisa y correcta, pero aquí también quiero mostrar formas de "definir" realmente los bloques.
¿Tonto? Si. ¿Útil? Genial. Aquí hay una forma diferente y "más atómica" de establecer la propiedad ... y una clase que es ridículamente útil ...
Esto ilustra la configuración de la propiedad de bloque a través del descriptor de acceso (aunque dentro de init, una práctica discutiblemente discutible ...) frente al mecanismo "getter" "no atómico" del primer ejemplo. En cualquier caso ... las implementaciones "codificadas" siempre se pueden sobrescribir, por ejemplo ... a lá ..
Además ... si desea agregar una propiedad de bloque en una categoría ... digamos que desea usar un Bloque en lugar de alguna "acción" de objetivo / acción de la vieja escuela ... Puede usar los valores asociados para, bueno ... asocia los bloques.
Ahora, cuando haces un botón, no tienes que configurar un
IBAction
drama ... Solo asocia el trabajo a realizar en la creación ...Este patrón puede aplicarse OVER y OVER a las API de Cocoa. Usar las propiedades de traer las partes pertinentes de su código más juntos , eliminar los paradigmas delegación contorneados , y aprovechar el poder de los objetos más allá de simplemente actuar como "contenedores" mudos.
fuente
Por supuesto, podría usar bloques como propiedades. Pero asegúrese de que se declaren como @property (copia) . Por ejemplo:
En MRC, los bloques que capturan variables de contexto se asignan en la pila ; se liberarán cuando se destruya el marco de la pila. Si se copian, se asignará un nuevo bloque en el montón , que se puede ejecutar más tarde después de que se apunte el marco de la pila.
fuente
Descargo de responsabilidad
Esto no pretende ser "la buena respuesta", ya que esta pregunta solicita explícitamente ObjectiveC. Cuando Apple presentó Swift en la WWDC14, me gustaría compartir las diferentes formas de usar bloque (o cierres) en Swift.
Hola swift
Tiene muchas formas de pasar un bloque equivalente a la función en Swift.
Encontré tres.
Para entender esto, le sugiero que pruebe en el patio este pequeño código.
Rápido, optimizado para cierres
Como Swift está optimizado para el desarrollo asincrónico, Apple trabajó más en los cierres. La primera es que la firma de la función se puede inferir para que no tenga que volver a escribirla.
Acceda a los parámetros por números
Inferencia de parámetros con nomenclatura
Cierre final
Este caso especial solo funciona si el bloque es el último argumento, se llama cierre final
Aquí hay un ejemplo (combinado con la firma inferida para mostrar el poder de Swift)
Finalmente:
Usar todo este poder lo que haría es mezclar el cierre final y la inferencia de tipos (con nombres para facilitar la lectura)
fuente
Hola swift
Complementando lo que respondió @Francescu.
Agregar parámetros adicionales:
fuente
Puede seguir el formato a continuación y puede usar la
testingObjectiveCBlock
propiedad en la clase.Para más información mira aquí
fuente