Je lis la documentation de Xcode, et voici quelque chose qui me laisse perplexe:
__block typeof(self) tmpSelf = self;
[self methodThatTakesABlock:^ {
[tmpSelf doSomething];
}];
Ce qui suit est copié de la documentation:
Un bloc constitue une référence forte aux variables qu'il capture. Si vous utilisez
self
dans un bloc, le bloc forme une référence forte àself
, donc siself
a également une référence forte au bloc (ce qu'il fait généralement), un fort cycle de référence en résulte. Pour éviter le cycle, vous devez créer un faible (ou__block
) référence à soi en dehors du bloc, comme dans l'exemple ci-dessus.
Je ne comprends pas ce qui fait un faible (ou __block
)' signifier?
Est
__block typeof(self) tmpSelf = self;
et
__weak typeof(self) tmpSelf = self;
exactement la même chose ici?
J'ai trouvé une autre pièce dans le document:
Remarque: dans un environnement récupéré, si vous appliquez les deux
__weak
et__block
modificateurs à une variable, alors le bloc ne s'assurera pas qu'il est maintenu en vie.
Donc, je suis totalement perplexe.
De la documentation sur __block
Les variables __block vivent dans un stockage partagé entre la portée lexicale de la variable et tous les blocs et copies de bloc déclarés ou créés dans la portée lexicale de la variable. Ainsi, le stockage survivra à la destruction de la trame de pile si des copies des blocs déclarés dans la trame survivent au-delà de la fin de la trame (par exemple, en étant mises en file d'attente quelque part pour une exécution ultérieure). Plusieurs blocs dans une portée lexicale donnée peuvent utiliser simultanément une variable partagée.
De la documentation sur __weak
__weak spécifie une référence qui ne maintient pas vivant l'objet référencé. Une référence faible est définie sur zéro lorsqu'il n'y a pas de références fortes à l'objet.
Ce sont donc des choses techniquement différentes. __block consiste à empêcher la copie de votre variable de votre portée externe dans votre portée de bloc. __weak est un pointeur faible auto-délimitant.
Notez que je l'ai dit techniquement, car pour votre cas, ils feront (presque) la même chose. La seule différence est que vous utilisiez ARC ou non. Si votre projet utilise ARC et est uniquement pour iOS4.3 et supérieur, utilisez __weak. Il garantit que la référence est définie sur nil si la référence de portée globale est libérée d'une manière ou d'une autre. Si votre projet n'utilise pas ARC ou concerne des versions de système d'exploitation plus anciennes, utilisez __block.
Il y a une différence subtile ici, assurez-vous de la comprendre.
EDIT: Une autre pièce du puzzle est __unsafe_unretained. Ce modificateur est presque le même que __weak mais pour les environnements d'exécution antérieurs à 4.3. CEPENDANT, il n'est pas réglé sur zéro et peut vous laisser des pointeurs suspendus.
En mode de comptage manuel des références, __block id x; a pour effet de ne pas conserver x. En mode ARC, __block id x; par défaut, il conserve x (comme toutes les autres valeurs). Pour obtenir le comportement du mode de comptage manuel des références sous ARC, vous pouvez utiliser __unsafe_unretained __block id x ;. Cependant, comme le nom __unsafe_unretained l'indique, avoir une variable non conservée est dangereux (car il peut osciller) et est donc déconseillé. Deux meilleures options sont soit d'utiliser __weak (si vous n'avez pas besoin de prendre en charge iOS 4 ou OS X v10.6), soit de définir la valeur __block sur nil pour rompre le cycle de conservation.
A côté d'autres réponses sur __block
contre __weak
, il existe un autre moyen d'éviter le cycle de rétention dans votre scénario.
@weakify(self);
[self methodThatTakesABlock:^ {
@strongify(self);
[self doSomething];
}];
Lorsque vous utilisez self in block, vous devez utiliser __ faible, pas __ block car il peut se conserver.
Dans le cas où vous avez besoin d'un moi fort, vous pouvez utiliser comme ceci:
__weak typeof(self) *weakSelf = self;
[self methodThatTakesABlock:^{
if (weakSelf) {
__strong typeof(self) *strongSelf = weakSelf;
[strongSelf doSomething];
}
}];