Pregunta

¿Es posible tener bloques como propiedades utilizando la sintaxis de la propiedad estándar?

¿Hay algún cambio para ARC

¿Fue útil?

Solución

@property (nonatomic, copy) void (^simpleBlock)(void);
@property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);

Si usted va a estar repitiendo el mismo bloque en varios lugares utilizan un tipo def

typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
@property (nonatomic) MyCompletionBlock completion;

Otros consejos

Este es un ejemplo de cómo se llevaría a cabo una tarea tan:

#import <Foundation/Foundation.h>
typedef int (^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];
}
@end

int main () {
    @autoreleasepool {
        myobj *ob = [[myobj alloc] init];
        ob.compare = ^
        {
            return rand();
        };
        NSLog(@"%i", ob.compare());
        // if not ARC
        [ob release];
    }

    return 0;
}

Ahora, lo único que tendría que cambiar si necesita cambiar el tipo de comparación sería el typedef int (^IntBlock)(). Si tiene que pasar dos objetos a la misma, cambiarlo a esto: typedef int (^IntBlock)(id, id), y cambiar su bloque para:

^ (id obj1, id obj2)
{
    return rand();
};

Espero que esto ayude.

EDITAR 12 marzo de 2012:

Para ARC, hay cambios requiere ninguna específica, como ARC gestionará los bloques para usted, siempre y cuando se definen como copia. No es necesario para establecer la propiedad a cero en su destructor, tampoco.

Para más lectura, por favor echa un vistazo a este documento: http://clang.llvm.org/docs/AutomaticReferenceCounting.html

Para Swift, sólo tiene que utilizar cierres: ejemplo

.

En Objective-C,

@property (copia) void (^ doStuff) (void);

Es así de simple.

documentación de Apple, que explica plenamente este problema:

de Apple mana.

En el archivo .h:

// 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á el 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();
    }

Cuidado de código de ejemplo fuera de fecha.

Con (2014+) sistemas modernos, hacer lo que se muestra aquí. Es así de simple. Espero que ayuda a alguien. Feliz Navidad 2013!

Por el amor posteridad / de integridad ... He aquí dos ejemplos completa de cómo implementar esta ridículamente versátil "forma de hacer las cosas". @ La respuesta de Robert es felizmente concisa y correcta, pero aquí quiero mostrar también formas de realidad "definir" los bloques.

@interface       ReusableClass : NSObject
@property (nonatomic,copy) CALayer*(^layerFromArray)(NSArray*);
@end

@implementation  ResusableClass
static  NSString const * 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"];
        }
        return list;
    };
}
@end

tonta? Sí. ¿Útil? Infiernos sí. Aquí es un diferente, forma "más atómica" de establecer la propiedad .. y una clase que es ridículamente útil ...

@interface      CALayoutDelegator : NSObject
@property (nonatomic,strong) void(^layoutBlock)(CALayer*);
@end

@implementation CALayoutDelegator
- (id) init { 
   return self = super.init ? 
         [self setLayoutBlock: ^(CALayer*layer){
          for (CALayer* sub in layer.sublayers)
            [sub someDefaultLayoutRoutine];
         }], self : nil;
}
- (void) layoutSublayersOfLayer:(CALayer*)layer {
   self.layoutBlock ? self.layoutBlock(layer) : nil;
}   
@end

Esto ilustra establecer la propiedad de bloque a través del descriptor de acceso (aunque init en el interior, una práctica discutiblemente dicey ..) vs del primer ejemplo mecanismo "no atómica" "getter". En cualquiera de los casos ... las implementaciones "codificado" siempre se puede sobrescribir, por ejemplo, .. A La ..

CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
  [layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;

También .. si desea agregar una propiedad de bloque en una categoría ... dicen que desee utilizar un bloque en lugar de algún objetivo de la vieja escuela / acción "acción" ... Usted sólo puede usar los valores asociados a, así .. asociar los bloques.

typedef    void(^NSControlActionBlock)(NSControl*); 
@interface       NSControl            (ActionBlocks)
@property (copy) NSControlActionBlock  actionBlock;    @end
@implementation  NSControl            (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 usted hace un botón, usted no tiene que configurar algo de drama IBAction .. Sólo asociar el trabajo a realizar en la creación ...

_button.actionBlock = ^(NSControl*thisButton){ 

     [doc open]; [thisButton setEnabled:NO]; 
};

Este patrón se puede aplicar una y otra vez a Cacao API. Usar las propiedades de traer las partes pertinentes de su código de más juntos , eliminar paradigmas delegación contorneados , y aprovechar el poder de los objetos más allá de simplemente actuar como "contenedores" mudos.

Por supuesto, usted podría utilizar bloques como propiedades. Pero asegúrese de que se declaran como @property (copiar) . Por ejemplo:

typedef void(^TestBlock)(void);

@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end

En MRC, bloques de captura de las variables de contexto se asignan en pila ; que se dará a conocer cuando el marco de pila se destruye. Si se copian, un nuevo bloque se asignará en heap , que puede ser ejecutado más tarde después de que la pila se poped.

Disclamer

Esto no pretende ser "la respuesta buena", ya que esta cuestión pidió explícitamente ObjectiveC. A medida que Apple introdujo Swift en el WWDC14, me gustaría compartir las diferentes formas de bloquear el uso (o el cierre) en Swift.

Hola, Swift

Hay muchas maneras que ofrece para pasar un bloque equivalente a la función en Swift.

He encontrado tres.

Para entender esto le sugiero a prueba en el parque esta pequeña pieza 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)

Swift, optimizado para cierres

Como Swift está optimizado para el desarrollo asíncrono, Apple trabajó más en los cierres. La primera es que la firma de la función puede ser inferida por lo que no tiene que volver a escribir.

Acceso params por números

let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })

Parámetros inferencia con nombrar

let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })

arrastra Cierre

Este caso especial sólo funciona si el bloque es el último argumento, se llama detrás de cierre

Este es un ejemplo (se fusionó con la firma inferido para mostrar el poder Swift)

let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }

Por último:

El uso de todo este poder lo que haría que se mezcla detrás de cierre y la inferencia de tipos (con nomenclatura para facilitar la lectura)

PFFacebookUtils.logInWithPermissions(permissions) {
    user, error in
    if (!user) {
        println("Uh oh. The user cancelled the Facebook login.")
    } else if (user.isNew) {
        println("User signed up and logged in through Facebook!")
    } else {
        println("User logged in through Facebook!")
    }
}

Hola, Swift

Como complemento a lo que respondió @Francescu.

Adición de parámetros adicionales:

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)

Se puede seguir el siguiente formato y se puede utilizar la propiedad testingObjectiveCBlock en la clase.

typedef void (^testingObjectiveCBlock)(NSString *errorMsg);

@interface MyClass : NSObject
@property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
@end

Para obtener más información echar un vistazo aquí

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top