Question

Est-il possible d'avoir des blocs comme des propriétés en utilisant la syntaxe de propriété standard?

Y at-il des changements pour ARC ?

Était-ce utile?

La solution

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

Si vous allez répéter le même bloc en plusieurs endroits utilisent un type def

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

Autres conseils

Voici un exemple de la façon dont vous accomplir une telle tâche:

#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;
}

Maintenant, la seule chose qui aurait besoin de changer si vous avez besoin de changer le type de comparaison serait le typedef int (^IntBlock)(). Si vous avez besoin de passer deux objets, changer à ceci: typedef int (^IntBlock)(id, id) et changer votre bloc à:

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

J'espère que cette aide.

EDIT 12 Mars, 2012:

Pour l'ARC, il n'y a pas spécifiques changements requis, comme ARC administrera les blocs pour vous aussi longtemps qu'ils sont définis comme copie. Vous n'avez pas besoin de définir la propriété à zéro dans votre destructor, que ce soit.

Pour plus de lecture, s'il vous plaît consulter ce document: http://clang.llvm.org/docs/AutomaticReferenceCounting.html

Pour Swift, il suffit d'utiliser les fermetures: exemple

.

Objective-C,

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

Il est aussi simple que cela.

la documentation d'Apple, expliquant en détail cette question:

d'Apple Doco.

Dans votre fichier .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".

Voici votre fichier .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();
    }

Méfiez-vous des exemples de code hors-jour.

Avec les systèmes modernes (2014+), faire ce qui est montré ici. Il est aussi simple que cela. Il aide quelqu'un l'espoir. Joyeux Noël 2013!

Pour l'amour de la postérité / rond ... Voici deux exemples complets sur la façon de mettre en œuvre cette ridiculement polyvalent « façon de faire ». @ La réponse de Robert est béatement concis et correct, mais ici, je veux montrer aussi des façons de réellement « définir » les blocs.

@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

idiot? Oui. utile? Hells oui. Voici une façon différente, "plus atomique" de définir la propriété .. et une classe qui est ridiculement utile ...

@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

Ceci illustre définissant la propriété de bloc via l'accesseur (bien que l'intérieur d'initialisation, une pratique risquée .. debatably) vs mécanisme « nonatomic » « getter » du premier exemple. Dans les deux cas ... les implémentations "" peuvent toujours codées en dur ECRASEES, par exemple .. un lá ..

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

De plus .. si vous voulez ajouter une propriété de bloc dans une catégorie ... dites que vous voulez utiliser un bloc au lieu d'une cible vieille école / action « action » ... Vous pouvez simplement utiliser les valeurs associées à, bien .. associer les blocs.

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

Maintenant, quand vous faites un bouton, vous ne devez pas mettre en place un drame de IBAction .. Il suffit d'associer le travail à faire à la création ...

_button.actionBlock = ^(NSControl*thisButton){ 

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

Ce modèle peut être appliqué reprises pour API Cocoa de. Utiliser les propriétés pour amener les parties pertinentes de votre code rapprocher , éliminer paradigmes de la délégation alambiquée , et de tirer parti de la puissance des objets au-delà de tout agir comme muets « conteneurs ».

Bien sûr, vous pouvez utiliser des blocs comme des propriétés. Mais assurez-vous qu'ils sont déclarés comme @property (copie) . Par exemple:

typedef void(^TestBlock)(void);

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

MRC, des blocs de capture des variables de contexte sont alloués dans pile ; ils seront libérés lorsque le cadre de la pile est détruite. S'ils sont copiés, un nouveau bloc sera attribué dans tas , qui peut être exécuté plus tard après que le cadre de pile est poped.

Désistement

Ce ne vise pas à être « la bonne réponse », comme cette question demande explicitement ObjectiveC. Comme Apple a introduit Swift au WWDC14, je voudrais partager les différentes façons de bloquer l'utilisation (ou la fermeture) à Swift.

Bonjour, Swift

Vous avez plusieurs façons proposées pour passer un équivalent bloc fonction Swift.

J'ai trouvé trois.

Pour comprendre cela, je vous suggère de tester dans la cour de ce petit morceau de code.

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, optimisé pour une fermeture

Swift est optimisé pour le développement asynchrone, Apple a travaillé plus sur les fermetures. La première est que la signature de fonction peut être déduit de sorte que vous n'avez pas à réécrire.

Accès params par des chiffres

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

params inférence de nommer

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

Fermeture Trailing

Ce cas particulier ne fonctionne que si le bloc est le dernier argument, il est appelé fermeture arrière

est un exemple ici (fusionné avec la signature inférée pour montrer la puissance Swift)

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

Enfin:

En utilisant tout ce pouvoir ce que je ferais est le mélange de fermeture de fuite et l'inférence de type (avec dénomination pour une meilleure lisibilité)

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!")
    }
}

Bonjour, Swift

En complément de ce que @Francescu a répondu.

Ajout de paramètres supplémentaires:

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)

Vous pouvez suivre le format ci-dessous et peut utiliser la propriété testingObjectiveCBlock dans la classe.

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

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

Pour plus d'informations allez voir ici

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top