2010-07-15 12 views
36

Je pensais juste, car vous pouvez traiter des Blocs comme des objets si j'en crée deux et les ajouter ensuite à un NSArray est-il possible de les exécuter à partir du tableau?Exécution de blocs à partir de NSArray?

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 @ davedelong d'excellente réponse

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]; 
+2

Bel ensemble de réponses .... J'ai vu le titre et espérais quelques points de rep. Les gens l'ont bien couvert. :) – bbum

+0

Juste un petit point, si vous ne copiez pas/relâchez le bloc sera en pile ... Donc si la pile est détruite, l'application va se bloquer correctement? – fzaziz

Répondre

29

Bien sûr, vous venez de invoquez avec () comme tout autre bloc, mais vous devez typecast la valeur de récupérer NSArray. Voici un exemple (avec un typedef ajouté, parce que sinon ma tête me fait mal):

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 
+0

ok, donc ne pas être familier avec les pointeurs de fonction suis-je obtenir ce droit? Le typedef définit "IntBlock" qui est un pointeur vers un bloc qui retourne un int et ne prend aucun argument. Je pense que je comprends, et en regardant l'alternative (dont je suis sûr que je me trompe) j'apprécie votre décision d'aller avec le typedef :) Très apprécié. – fuzzygoat

+0

Oui, vous l'avez. –

+1

Vous n'avez pas besoin de le lancer. Cela fonctionne très bien pour faire 'int (^ block)() = [array objectAtIndex: 0]'. Un pointeur est un pointeur, après tout, au moins dans les langages de bas niveau comme 'C' et ses dérivés. – aroth

6

Bien sûr, vous pouvez.

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

J'ai considéré ceci, très intéressant. Pouvez-vous clarifier pour moi, ai-je raison de me référer à "int (^ x) (void)" comme pointeur sur un bloc? J'essaie juste de m'assurer que la terminologie est correcte. – fuzzygoat

60

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

Lors de la création d'un NSArray avec des objets, il sera retain les objets mis en elle. Dans le cas des blocs, il utilise la fonction Block_retain. 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 rares exemples d'objets Objective-C qui peuvent être créés sur la pile sans plonger dans des astuces absurdes). Cela signifie que dès que cette méthode se termine, votre tableau pointe vers la poubelle, car les blocs vers lesquels il pointait n'existent plus. Pour ce faire 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 vous déplacez explicitement le bloc hors de la pile et sur le tas, où il peut en toute sécurité rester après la méthode/sortie de la fonction . Ensuite, après avoir ajouté les blocs au tableau, vous devez équilibrer votre copy (en raison de la règle NARC) avec un appel ultérieur au release. Avoir du sens?

+0

Salut Dave, oui je comprends, je n'étais pas au courant des blocs créés sur la pile (juste commencé à regarder les blocs aujourd'hui). Très appréciée. – fuzzygoat

+0

Excellent point sur la nécessité de copier –

+0

Salut Dave, j'ai trouvé cette question et la réponse acceptée de David Gelhar donc je l'ai implémentée et ça a plutôt bien fonctionné, ça ** n'a pas crashé. En lisant plus loin, votre réponse a du sens mais n'explique pas pourquoi le code de David ne plante pas (immédiatement?). Avez-vous la moindre idée? – Tieme