objective-c completion block




Que signifie le mot clé "__block"? (5)

@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 ne conserve pas. C'est à vous de conserver et de libérer, au besoin.
...

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

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

Que signifie exactement le mot-clé __block dans Objective-C? Je sais que cela vous permet de modifier les variables dans les blocs, mais j'aimerais savoir ...

  1. Que dit-il exactement au compilateur?
  2. Est-ce que ça fait autre chose?
  3. Si c'est tout ce qu'il fait alors pourquoi est-il nécessaire en premier lieu?
  4. Est-ce dans les docs partout? (Je ne peux pas le trouver).

De la spécification du langage de bloc :

En plus du nouveau type de bloc, nous introduisons un nouveau qualificatif de stockage, __block, pour les variables locales. [testme: une déclaration __block dans un bloc littéral] Le qualificateur de stockage __block est mutuellement exclusif aux qualificateurs de stockage local existants auto, register et static. [testme] Les variables qualifiées par __block agissent comme si elles étaient dans le stockage alloué et ce stockage est récupéré automatiquement 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 le stockage alloué (heap) sur une copie de bloc d'un bloc de référence. De telles 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 le stockage alloué et est supposée faire référence à un bloc qui est également dans le stockage alloué (c'est le résultat d'une opération Block_copy). Malgré cela, il n'est pas prévu de faire une Block_copy ou une Block_release si une implémentation fournit un stockage automatique initial pour les Blocs. Cela est dû à la condition de concurrence inhérente de potentiellement plusieurs threads qui tentent de mettre à jour la variable partagée et le besoin de synchronisation autour de la disposition des anciennes valeurs et de la copie de nouvelles. Une telle synchronisation dépasse la portée de cette spécification de langage.

Pour plus de détails sur la compilation d'une variable __block, voir la section 2.3, Spécification d' implémentation de bloc .


J'espère que ceci vous aidera

Supposons que nous ayons un code comme:

{
     int stackVariable = 1;

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

il donnera une erreur comme "variable n'est pas assignable" parce que la variable de pile à l'intérieur du bloc est par défaut immuable.

ajouter __block (modificateur de stockage) avant la déclaration make mutable à l'intérieur du bloc ie __block int stackVariable=1;


Normalement, lorsque vous n'utilisez pas __block, le bloc copie (conserve) la variable, donc même si vous modifiez la variable, le bloc a accès à l'ancien objet.

NSString* str = @"hello";
void (^theBlock)() = ^void() {
    NSLog(@"%@", str);
};
str = @"how are you";
theBlock(); //prints @"hello"

Dans ces 2 cas, vous avez besoin de __block:

1.Si vous voulez modifier la variable à l'intérieur du bloc et attendez qu'elle soit visible à l'extérieur:

__block NSString* str = @"hello";
void (^theBlock)() = ^void() {
    str = @"how are you";
};
theBlock();
NSLog(@"%@", str); //prints "how are you"

2.Si vous voulez modifier la variable après avoir déclaré le bloc et que vous attendez du bloc pour voir la modification:

__block NSString* str = @"hello";
void (^theBlock)() = ^void() {
    NSLog(@"%@", str);
};
str = @"how are you";
theBlock(); //prints "how are you"

__block est un qualificateur de stockage pouvant être utilisé de deux manières:

  1. Marque qu'une variable réside dans un stockage partagé entre la portée lexicale de la variable d'origine et tous les blocs déclarés dans cette portée. Et clang va générer une structure pour représenter cette variable, et utiliser cette structure par référence (pas par valeur).

  2. Dans MRC, __block peut être utilisé pour éviter de conserver les variables d'objet capturées par un bloc. Attention que cela ne fonctionne pas pour ARC. Dans ARC, vous devriez utiliser __weak à la place.

Vous pouvez vous référer au document Apple pour des informations détaillées.







objective-c-blocks