37 votes

Exécution de blocs à partir de NSArray ?

Je me disais juste que, comme on peut traiter les blocs comme des objets, si j'en crée deux et que je les ajoute à un tableau NSArray, y a-t-il un moyen de les exécuter à partir de ce tableau ?

int (^Block_001)(void) = ^{ return 101; };
int (^Block_002)(void) = ^{ return 202; };
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil];

EDIT : Mise à jour pour plus de clarté Par l'excellente réponse de @davedelong

int (^Block_001)(void) = [^{ return 101; } copy];
int (^Block_002)(void) = [^{ return 202; } copy];
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil];

[Block_001 release];
[Block_002 release];

60voto

Dave DeLong Points 156978

@KennyTM et @David ont raison, mais votre code est potentiellement erroné. Voici pourquoi :

Lors de la création d'un NSArray avec des objets, il retain les objets qui y sont placés. Dans le cas des blocs, il s'agit d'utiliser la fonction Block_retain fonction. Cela signifie que le tableau a conservé les blocs que vous avez créés, mais qui vivent sur la pile (les blocs sont l'un des très rares exemples d'objets Objective-C qui peuvent être créés sur la pile sans avoir recours à des astuces absurdes). Cela signifie que dès que cette méthode sort, votre tableau pointe maintenant vers des déchets, parce que les blocs vers lesquels il pointait auparavant n'existent plus . Pour faire cela correctement, vous devez faire :

int (^Block_001)(void) = [^{ return 101; } copy];
int (^Block_002)(void) = [^{ return 202; } copy];
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil];

[Block_001 release];
[Block_002 release];

En invoquant copy sur le bloc, vous déplacez explicitement le bloc de la pile vers le tas, où il peut rester en toute sécurité après la sortie de la méthode/fonction. Ensuite, après avoir ajouté les blocs au tableau, vous devez équilibrer vos blocs de la pile et du tas. copy (à cause de la règle NARC) avec un appel ultérieur à release . Vous comprenez ?

29voto

David Gelhar Points 20703

Bien sûr, il suffit de l'invoquer avec () comme n'importe quel autre bloc, mais vous devez taper la valeur que vous récupérez à partir de NSArray . Voici un exemple (avec un typedef ajouté, parce que sinon j'ai mal à la tête) :

typedef int (^IntBlock)(void);
IntBlock Block_001 = ^{ return 101; };
IntBlock Block_002 = ^{ return 202; };
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil];
int x = ((IntBlock)[array objectAtIndex:0]) (); // now x == 101

7voto

KennyTM Points 232647

Bien sûr que vous pouvez.

int (^x)(void) = [array objectAtIndex:0];
printf("%d\n", x()); // prints 101.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X