Que signifie exactement le mot clé __block
dans Objective-C? Je sais que cela vous permet de modifier des variables dans des blocs, mais j'aimerais savoir ...
Il indique au compilateur que toute variable marquée par celle-ci doit être traitée de 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 les blocs sont copiés. Par conséquent, aucune modification apportée à ces variables ne s'affiche en dehors du bloc. Lorsqu'ils sont marqués avec __block
, les modifications effectuées à l'intérieur du bloc sont également visibles à l'extérieur de celui-ci.
Pour un exemple et plus d'informations, voir Le type de stockage __block dans les rubriques de programmation Blocks d'Apple.
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, localCounter
et localCharacter
sont modifiés avant l'appel du bloc. Toutefois, dans le bloc, seule la modification de localCharacter
serait visible, grâce au mot clé __block
. Inversement, le bloc peut modifier localCharacter
et cette modification est visible à l'extérieur du bloc.
@bbum couvre les blocs en profondeur dans un blog post et touche au type de stockage __block.
__block est un type de stockage distinct
Tout comme statique, automatique 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;
__block est un qualificateur de stockage qui peut être utilisé de deux manières:
Indique qu'une variable habite 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 générera une structure pour représenter cette variable et utilisera cette structure par référence (pas par valeur).
Dans MRC, __block peut être utilisé pour éviter de conserver les variables d'objet qu'un bloc capture. Attention, cela ne fonctionne pas pour ARC. Dans ARC, vous devriez plutôt utiliser __weak.
Vous pouvez vous référer à doc Apple pour des informations détaillées.
Normalement, lorsque vous n'utilisez pas __block, le bloc copie (conserve) la variable. Ainsi, 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 souhaitez modifier la variable à l'intérieur du bloc et vous attendez à ce 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 souhaitez modifier la variable après avoir déclaré le bloc et attendez-vous à ce que le bloc voie le changement:
__block NSString* str = @"hello";
void (^theBlock)() = ^void() {
NSLog(@"%@", str);
};
str = @"how are you";
theBlock(); //prints "how are you"
__block
est un type de stockage utilisé pour rendre les variables de portée mutables. Plus franchement, si vous déclarez une variable avec ce spécificateur, sa référence sera transmise à des blocs et non à une copie en lecture seule. Pour plus de détails, voir Blocs Programmation sous iOS
De la Spécification du langage de bloc :
En plus du nouveau type de bloc, nous introduisons également un nouveau qualificateur de stockage, __block, pour les variables locales. [testme: une déclaration __block dans un littéral de bloc] Le qualificatif de stockage __block est mutuellement exclusif des 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 que ce stockage est récupéré automatiquement après la dernière utilisation de ladite variable. Une mise en œuvre peut choisir une optimisation dans laquelle le stockage est initialement automatique et uniquement "déplacé" vers le stockage alloué (tas) lors d'une copie de bloc d'un bloc référent. De telles variables peuvent être mutées comme les variables normales.
Dans le cas où une variable __block est un bloc, il faut supposer que la variable __block réside dans la mémoire allouée et qu’elle est donc supposée faire référence à un bloc également dans la mémoire allouée (résultat d’une opération Block_copy). Malgré cela, il n’est pas prévu de faire un Block_copy ou un Block_release si une implémentation fournit un stockage automatique initial pour Blocks. Cela est dû à la situation de concurrence intrinsèque de plusieurs threads potentiellement tentant de mettre à jour la variable partagée et au besoin de synchronisation pour éliminer les anciennes valeurs et en copier de nouvelles. Une telle synchronisation dépasse le cadre de cette spécification de langage.
Pour plus d'informations sur la compilation d'une variable __block, reportez-vous à la section Block Implementation Spec , section 2.3.
j'espère que ceci vous aidera
supposons que nous ayons un code comme:
{
int stackVariable = 1;
blockName = ^()
{
stackVariable++;
}
}
cela donnera une erreur comme "variable n'est pas assignable" car les variables de pile à l'intérieur du bloc sont par défaut immuables.
l'ajout de __block (modificateur de stockage) avant la déclaration permet de le rendre mutable à l'intérieur du bloc i.e __block int stackVariable=1;
Cela signifie que la variable à laquelle il est préfixé est disponible pour être utilisée dans un bloc.