461 votes

Que signifie le mot-clé "__block" ?

Que fait exactement le __block en Objective-C ? Je sais qu'il permet de modifier des variables à l'intérieur de blocs, mais j'aimerais savoir...

  1. Que dit-elle exactement au compilateur ?
  2. Est-ce qu'il fait autre chose ?
  3. Si c'est tout ce qu'il fait, alors pourquoi est-il nécessaire en premier lieu ?
  4. Est-ce que cela figure dans la documentation ? (Je ne le trouve pas).

3 votes

Vérifier aquí et la section "Blocs et variables".

1 votes

0 votes

@Vincent ack, merci j'avais oublié cette section ! Je vais y jeter un coup d'oeil.

560voto

DarkDust Points 47584

Elle indique au compilateur que toute variable marquée par elle doit être traitée d'une manière spéciale lorsqu'elle est utilisée à l'intérieur d'un bloc. Normalement, les variables et leur contenu qui sont également utilisés dans des blocs sont copiés, donc toute modification apportée à ces variables n'apparaît pas en dehors du bloc. Lorsqu'elles sont marquées par __block les modifications effectuées à l'intérieur du bloc sont également visibles à l'extérieur de celui-ci.

Pour un exemple et de plus amples informations, voir Le type de stockage __block dans le site d'Apple Blocs Sujets de programmation .

L'exemple important est celui-ci :

extern NSInteger CounterGlobal;
static NSInteger CounterStatic;

{
    NSInteger localCounter = 42;
    __block char localCharacter;

    void (^aBlock)(void) = ^(void) {
        ++CounterGlobal;
        ++CounterStatic;
        CounterGlobal = localCounter; // localCounter fixed at block creation
        localCharacter = 'a'; // sets localCharacter in enclosing scope
    };

    ++localCounter; // unseen by the block
    localCharacter = 'b';

    aBlock(); // execute the block
    // localCharacter now 'a'
}

Dans cet exemple, les deux localCounter y localCharacter sont modifiés avant que le bloc ne soit appelé. Cependant, à l'intérieur du bloc, seule la modification de l'élément localCharacter serait visible, grâce à la __block mot-clé. Inversement, le bloc peut modifier localCharacter et cette modification est visible en dehors du bloc.

9 votes

Une explication excellente et concise, et un exemple très utile. Merci !

1 votes

Comment le aBlock modifie-t-il localCounter ? Il semble seulement modifier CounterGlobal. Merci

8 votes

Il ne modifie pas localCounter mais il modifie localCharacter . Faites également attention à la valeur localCounter a dans le bloc : c'est 42, même si la variable est augmentée avant le bloc est appelé mais après le bloc a été créé (c'est à ce moment-là que la valeur a été "capturée").

28voto

Joe Points 37343

@bbum couvre les blocs en profondeur dans un article de blog et touche au type de stockage __block.

__block est un type de stockage distinct

Tout comme static, auto et volatile, __block est un type de stockage. Il indique au compilateur que le stockage de la variable doit être géré différemment.

...

Cependant, pour les variables __block, le bloc n'est pas retenu. C'est à vous de les conserver et de les libérer, selon les besoins.
...

En ce qui concerne les cas d'utilisation, vous trouverez __block est parfois utilisé pour éviter les cycles de conservation puisqu'il ne conserve pas l'argument. Un exemple courant est l'utilisation de self.

//Now using myself inside a block will not 
//retain the value therefore breaking a
//possible retain cycle.
__block id myself = self;

0 votes

Voir cet article pour plus d'informations sur le problème du cycle de maintien : benscheirman.com/2012/01/ . Est-ce que __weak suffirait-il également dans ce cas précis ? C'est un peu plus clair peut-être...

17 votes

Enfin, l'affirmation selon laquelle __block peut être utilisé pour éviter les cycles de référence forte (alias cycles de rétention) est tout simplement fausse dans un contexte ARC. Étant donné qu'en ARC, __block provoque la référence forte de la variable, il est en fait plus susceptible de les provoquer. stackoverflow.com/a/19228179/189006

6voto

mithilesh Points 454

__block est un type de stockage qui est utilisé pour rendre les variables mutables, plus franchement si vous déclarez une variable avec ce spécificateur, sa référence sera transmise aux blocs et non une copie en lecture seule pour plus de détails voir Programmation par blocs dans iOS

2voto

Martin Gordon Points 19587

De la Spécification du langage des blocs :

En plus du nouveau type Block, nous introduisons également un nouveau qualificatif de stockage, __block, pour les variables locales. [Le qualificatif de stockage __block est mutuellement exclusif des qualificatifs de stockage local existants auto, register et static [testme] Les variables qualifiées par __block agissent comme si elles étaient dans un stockage alloué et ce stockage est automatiquement récupéré après la dernière utilisation de ladite variable. Une implémentation peut choisir une optimisation où le stockage est initialement automatique et seulement "déplacé" vers un stockage alloué (tas) lors d'une Block_copy d'un Block de référence. Ces variables peuvent être mutées comme le sont les variables normales.

Dans le cas où une variable __block est un bloc, il faut supposer que la variable __block réside dans un espace de stockage alloué et qu'elle est donc supposée faire référence à un bloc qui se trouve également dans un espace de stockage alloué (qu'elle est le résultat d'une opération Block_copy). Malgré cela, il n'y a aucune disposition pour effectuer une Block_copy ou une Block_release si une implémentation fournit un stockage automatique initial pour les blocs. Ceci est dû à la condition de course inhérente à la présence de plusieurs threads essayant de mettre à jour la variable partagée et au besoin de synchronisation autour de l'élimination des anciennes valeurs et de la copie des nouvelles. Une telle synchronisation dépasse le cadre de cette spécification de langage.

Pour plus de détails sur ce que doit donner une variable __block lors de la compilation, voir le document Spéc. de mise en œuvre des blocs , section 2.3.

0 votes

Vos liens sont tous les deux morts

0 votes

Ce n'est pas vraiment une réponse et elle pourrait être étoffée ou supprimée. Merci.

2voto

user3767017 Points 1

J'espère que cela vous aidera

Supposons que nous ayons un code comme :

{
     int stackVariable = 1;

     blockName = ^()
     {
      stackVariable++;
     }
}

il donnera une erreur du type "variable non assignable" car les variables de la pile à l'intérieur du bloc sont par défaut immuables.

en ajoutant __block (modificateur de stockage) devant la déclaration, on la rend mutable à l'intérieur du bloc, par exemple __block int stackVariable=1;

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