Concept
Tout est dans le nombre de retenues. L'ARC est une commodité, pour éviter aux développeurs de se soucier de conserver et de libérer manuellement. À la base, une variable forte augmentera le nombre de retenues de 1, alors qu'une variable faible ne le fera pas.
Voir ci-dessous :
@interface Test () {
NSString* strongVariable; // Instance variables default to strong
__weak NSString* weakVariable;
}
@end
// This has a retain count of 1, it has been allocated to memory by the user, and stored in a local variable (which is strong)
NSString* str = [[NSString alloc] initWithString:@"Test"];
// The string object will now have a retain count of 2, as the strong variable has increased its retain count
strongVariable = str;
// This weak variable does **not** increase the retain count, and as such it will still be 2
weakVariable = str;
// --
// Now, lets remove some references
// This will reduce the retain count to 1, as a strong variable has lost its link
strongVariable = nil;
// This will also reduce the retain count, as another strong variable has lost it's reference. This means the retain count is 0, and the object can now be considered to not exist
str = nil;
// What happens to weakVariable?
// Because it is referencing an object with a 0 retain count, the runtime will set the value of this variable automatically to nil (iOS 5 and above).
NSLog(@"%@", (weakVariable == nil) ? @"nil" : @"Not nil") // Will print "nil"
Vous ne pouvez pas vous retrouver dans une situation où une variable forte fait référence à un objet dont le nombre de conservations est de 0, cela va à l'encontre du concept de base d'une variable forte. Il convient de noter que, parallèlement à __weak
il y a __unsafe_unretained
. Cela agit comme une variable faible, sauf qu'elle n'est pas automatiquement mise à nil une fois que le compte de retenue atteint zéro, ce qui signifie qu'elle contiendra un pointeur vers une partie aléatoire de la mémoire (et se plantera si vous y accédez, vous devez la mettre à nil vous-même). La raison pour laquelle ce problème existe est due au fait qu'iOS 4 supporte l'ARC, mais pas la fonction __weak
. Dans la plupart des cas, vous utiliserez __weak
.
La description ci-dessus n'est qu'un aperçu pratique, vous pouvez lire beaucoup plus en profondeur en utilisant cette documentation.
Applications pratiques
Tout est __strong
par défaut. Si vous voulez des valeurs faibles, vous devez utiliser __weak
.
Vous utiliserez typiquement des variables faibles lorsque vous ne voulez pas conceptuellement propre un objet particulier. Si une voiture est propriétaire de son moteur et de ses roues, le conducteur ne l'est pas.
Wheel* wheel;
Engine* engine;
__weak Driver* driver;
À l'inverse, un conducteur serait propriétaire de la voiture.
Car* car;
Si la voiture appartenait au conducteur, nous aurions un conserver le cycle . La voiture possède le conducteur, et le conducteur possède la voiture. Si nous libérions l'un, qu'arriverait-il à l'autre ? L'ensemble du concept de cycles de retenue dépasse le cadre de cette question, mais vous pouvez lire à ce sujet ici.
Le même concept s'applique aux modèles de programmation, par exemple les délégués. Pour une vue de table, le contrôleur de vue possède la vue de table, mais la vue de table ne possède pas le contrôleur de vue (qui est utilisé comme un délégué).
//ViewController
UITableView* tableView;
tableView.delegate = self;
//UITableView
@property (nonatomic, weak) id<UITableViewDelegate> delegate;
Gotchas
Une utilisation sérieuse de __weak
est à quelques pâtés de maisons. Sans eux, vous risquez fort de provoquer des cycles de rétention sans vous en rendre compte. Encore une fois, cela dépasse le cadre de cette question, mais voir ici pour plus d'informations .
Analogie avec C++
Dans TR1, vous avez la possibilité d'utiliser des pointeurs partagés, ce qui vous permet de placer un objet alloué au tas dans un objet alloué à la pile, et de gérer la mémoire pour nous. Il gère la mémoire pour nous. Il le fait en utilisant le comptage de références. Chaque fois que vous passez le pointeur partagé à une autre variable, le compte de référence est incrémenté. Ceci est analogue à l'assignation à une variable forte dans Obj-C.