ARC Objective-C: fort vs retenir et faible vs assigner

367

Il existe deux nouveaux attributs de gestion de la mémoire pour les propriétés introduites par ARC stronget weak.

En dehors de copyce qui est évidemment quelque chose de complètement différent, y a-t-il des différences entre strongvs retainet weakvs assign?

D'après ma compréhension, la seule différence ici est que le pointeur weaksera assigné nil, alors que assignce ne sera pas le cas, ce qui signifie que le programme se bloquera lorsque j'enverrai un message au pointeur une fois qu'il sera libéré. Mais si j'utilise weak, cela n'arrivera jamais, car envoyer un message à nilne fera rien.

Je ne connais aucune différence entre stronget retain.

Y a-t-il une raison pour laquelle je devrais utiliser assignet retaindans de nouveaux projets, ou est-ce que le type est déconseillé?

Jakub Arnold
la source
12
Il y a trois nouveaux attributs de gestion de la mémoire pour les propriétés introduites par l' ARC strong, weaket unsafe_unretained.
NJones
5
@NJones Il y a deux attributs de propriété ( weaket strong) et 4 qualificatifs à vie variables ( __strong, __weak, __unsafe_unretained, __autoreleasing). Voir les notes ARC ci-dessous.
Snowcrash
1
@SnowCrash Il y avait une version de Xcode, probablement un aperçu du développeur, dans laquelle l'utilisation assignlors de la compilation avec ARC était une erreur. Il existe de nombreuses réponses supprimées à ce sujet. Il semble que cela ait été changé avant la version finale. unsafe_unretainedest l'attribut préféré de beaucoup d'entre nous parmi les premiers à adopter. Pour la preuve qu'il unsafe_unretaineds'agit d'un attribut valide, consultez "Programmation avec Objective-C" d'Apple dans la section "Encapsulation de données" sous le sous-titre "Utiliser des références non conservées non sécurisées pour certaines classes". Qui dit: "Pour une propriété, cela signifie utiliser l'attribut unsafe_unretained:"
NJones

Réponses:

230

De la transition vers les notes de version ARC (l'exemple de la section sur les attributs de propriété).

// The following declaration is a synonym for: @property(retain) MyClass *myObject;

@property(strong) MyClass *myObject;

C'est strongla même chose que retaindans une déclaration de propriété.

Pour les projets ARC que j'utiliserais à la strongplace retain, j'utiliserais assignpour les propriétés primitives C et weakpour les références faibles aux objets Objective-C.

JeremyP
la source
11
En fait, sous ARC, c'est une erreur de compilation à utiliser assignpour un objet. Vous devez utiliser soit weakou unsafe_unretained(ce qui n'est pas sûr, évidemment) si vous ne souhaitez pas conserver la propriété.
cobbal
5
assigncompile très bien pour moi dans les projets ARC avec la cible de déploiement 4.0.
Pascal
8
@Pascal: les références faibles ne sont pas autorisées dans les cibles de déploiement où le système d'exploitation n'est pas 5.0 ou supérieur. Donc, pour les projets plus anciens, vous pouvez toujours utiliser assign, mais si vous passez à des versions plus récentes, vous devez passer à faible
Mattia
1
Ressemble Xcode 4 (avec ARC) génère NSManagedObject sous - classes en utilisant retainvs. strong. Je suppose que c'est surtout inoffensif, mais j'imagine que cela devrait être strongpour la cohérence ... ou peut-être que cela n'a pas d'importance. stackoverflow.com/questions/7796476/…
Joe D'Andrea
3
@JeremyP Oui, votre réponse est parfaite. Je réagissais à @Mattia. Je faisais remarquer que cela assignest toujours valable dans certains cas.
Steven Oxley
606

Après avoir lu tant d'articles Stackoverflow et d'applications de démonstration pour vérifier les attributs des propriétés variables, j'ai décidé de rassembler toutes les informations sur les attributs:

  1. atomique // par défaut
  2. non anatomique
  3. fort = conserver // par défaut
  4. faible
  5. conserver
  6. assign // par défaut
  7. unsafe_unretained
  8. copie
  9. lecture seulement
  10. readwrite // par défaut

Ci-dessous le lien détaillé de l'article où vous pouvez trouver tous les attributs mentionnés ci-dessus, qui vous aideront certainement. Un grand merci à toutes les personnes qui donnent les meilleures réponses ici !!

Attributs de propriétés variables ou modificateurs dans iOS

1. fort (iOS4 = conserver)

  • il dit "garder cela dans le tas jusqu'à ce que je ne le pointe plus"
  • en d'autres termes "je suis le propriétaire, vous ne pouvez pas désallouer ceci avant de viser bien avec le même que conserver"
  • Vous utilisez fort uniquement si vous devez conserver l'objet.
  • Par défaut, toutes les variables d'instance et les variables locales sont des pointeurs puissants.
  • Nous utilisons généralement Strong pour UIViewControllers (les parents de l'élément d'interface utilisateur)
  • strong est utilisé avec ARC et il vous aide essentiellement, en ne vous souciant pas du nombre de rétentions d'un objet. ARC le libère automatiquement pour vous lorsque vous en avez terminé. L'utilisation du mot clé strong signifie que vous êtes propriétaire de l'objet.

Exemple:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2. faible -

  • il dit "gardez cela aussi longtemps que quelqu'un d'autre le montre fortement"
  • la même chose que l'attribution, aucune conservation ou libération
  • Une référence "faible" est une référence que vous ne conservez pas.
  • Nous utilisons généralement faible pour IBOutlets (UIViewController Childs). Cela fonctionne parce que l'objet enfant ne doit exister que tant que l'objet parent le fait.
  • une référence faible est une référence qui ne protège pas l'objet référencé de la collecte par un garbage collector.
  • Le faible est essentiellement assigné, une propriété non retenue. Sauf lorsque l'objet est désalloué, le pointeur faible est automatiquement défini sur zéro

Exemple :

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;

Explication forte et faible, merci à BJ Homer :

Imaginez que notre objet soit un chien et que le chien veuille s'enfuir (être désalloué).

Les pointeurs puissants sont comme une laisse sur le chien. Tant que la laisse est attachée au chien, le chien ne s'enfuira pas. Si cinq personnes attachent leur laisse à un chien (cinq pointeurs puissants vers un objet), le chien ne s'enfuira pas tant que les cinq laisses ne seront pas détachées.

Les pointeurs faibles, par contre, sont comme des petits enfants qui pointent vers le chien et disent "Regardez! Un chien!" Tant que le chien est toujours en laisse, les petits enfants peuvent toujours voir le chien et ils le pointeront toujours. Dès que toutes les laisses sont détachées, le chien s'enfuit, peu importe le nombre de petits enfants qui le désignent.

Dès que le dernier pointeur fort (laisse) ne pointe plus sur un objet, l'objet sera désalloué et tous les pointeurs faibles seront mis à zéro.

Lorsque nous utilisons faible?

La seule fois que vous voudriez utiliser faible, c'est si vous voulez éviter les cycles de rétention (par exemple, le parent retient l'enfant et l'enfant conserve le parent afin qu'aucun des deux ne soit jamais libéré).

3. retenir = fort

  • elle est conservée, l'ancienne valeur est libérée et elle est affectée conserver spécifie la nouvelle valeur doit être envoyée
  • conserver la cession et l'ancienne valeur envoyée
  • conserver est le même que fort.
  • Apple dit que si vous écrivez, il sera automatiquement converti / fonctionnera comme fort uniquement.
  • des méthodes comme «alloc» incluent un «retenir» implicite

Exemple:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4. attribuer

  • assign est la valeur par défaut et effectue simplement une affectation de variable
  • assign est un attribut de propriété qui indique au compilateur comment synthétiser l'implémentation du setter de la propriété
  • J'utiliserais assign pour les propriétés primitives C et faible pour les références faibles aux objets Objective-C.

Exemple:

@property (nonatomic, assign) NSString *address;

@synthesize address;
swiftBoy
la source
5
2. "une référence faible est une référence qui ne protège pas l'objet référencé de la collecte par un garbage collector" - il n'y a rien dans l'objectif c comme garbage collector;
bucherland
1
et cette hiérarchie est gérée automatiquement par iOS. En savoir plus sur le concept MVC. Je veux dire que lorsque ViewContorller est présenté, iOS charge sa hiérarchie de vues à l'écran (créant des vues manquantes). Lorsque d'autres ViewController sont présentés, cette première hiérarchie de vues est désallouée. Mais si vous avez «fort» dans ViewController, cette vue ne peut pas être désallouée lorsqu'elle est hors écran. Ce qui pourrait avoir un impact important sur la mémoire de l'appareil et provoquer un ralentissement de l'application. (Bien sûr, l'appareil a beaucoup de mémoire et vous iriez certainement bien sur une application d'écran 5-10, mais dans une application énorme, vous aurez des ennuis)
bucherland
1
Lorsque nous utilisons faible? 1. Pour les objets d'interface utilisateur, 2. délégués, 3. blocs (faibleSelf devrait être utilisé à la place de self pour éviter les cycles de mémoire (comme cela a été mentionné ci-dessus)
bucherland
1
Il y a une erreur dans cette excellente réponse - forte - "ARC la libère automatiquement pour vous quand vous en avez fini", ce n'est pas vrai. ARC libérera automatiquement les objets faibles lorsqu'il n'y a pas de pointeurs vers eux. Strong - est synonyme de conserver, donc l'objet est conservé et il est de notre responsabilité de rendre l'objet nul
Ashwin G
1
@RDC, qu'est-ce que cela defaultsignifie? Si je l'utilise @property (nonatomic) NSString *stringc'est strong? Ou assign? Parce que les deux sont des valeurs par défaut.
Iulian Onofrei
40

non atomique / atomique

  • non atomique est beaucoup plus rapide qu'atomique
  • utilisez toujours nonatomic sauf si vous avez une exigence très spécifique pour atomic, ce qui devrait être rare (atomic ne garantit pas la sécurité des threads - ne bloque l'accès à la propriété que lorsqu'elle est simultanément définie par un autre thread)

fort / faible / assigner

  • utiliser fort pour conserver les objets - bien que le mot clé retenir soit synonyme, il vaut mieux utiliser fort à la place
  • utilisez faible si vous voulez uniquement un pointeur sur l'objet sans le conserver - utile pour éviter les cycles de rétention (c'est-à-dire les délégués) - il supprimera automatiquement le pointeur lorsque l'objet sera relâché
  • utilisez assign pour les primitives - exactement comme faible, sauf qu'il n'élimine pas l'objet lorsqu'il est libéré (défini par défaut)

(Optionnel)

copie

  • l'utiliser pour créer une copie superficielle de l'objet
  • bonne pratique pour toujours définir des propriétés immuables à copier - parce que les versions mutables peuvent être passées dans des propriétés immuables, la copie garantira que vous aurez toujours affaire à un objet immuable
  • si un objet immuable est transmis, il le conservera - si un objet mutable est transmis, il le copiera

lecture seulement

  • l'utiliser pour désactiver le paramétrage de la propriété (empêche le code de se compiler en cas d'infraction)
  • vous pouvez changer ce qui est fourni par le getter en changeant la variable directement via sa variable d'instance, ou dans la méthode getter elle-même
Vadoff
la source
@Sakthimuthiah a raison, vous devez corriger votre réponse.
Adela Toderici
@Sakthimuthiah est incorrect (et tous ceux qui le disent). Atomic ne le rend PAS sûr pour les threads, bien qu'il puisse être facilement confondu en raison de son comportement. Veuillez lire: stackoverflow.com/questions/12347236/…
Chris J
39

Pour autant que je sache, stronget retainsont des synonymes, ils font donc exactement la même chose.

Ensuite, le weakest presque comme assign, mais automatiquement défini sur nil après que l'objet, il pointe vers, est désalloué.

Cela signifie que vous pouvez simplement les remplacer.

Cependant , il y a un cas spécial que j'ai rencontré, où j'ai dû utiliser assignplutôt que weak. Disons que nous avons deux propriétés delegateAssignet delegateWeak. Dans les deux est stocké notre délégué, qui nous possède en ayant la seule référence forte. Le délégué désalloue, donc notre -deallocméthode est appelée aussi.

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething];
    [delegateAssign doSomething];
}

Le délégué est déjà en processus de désallocation, mais n'est pas encore entièrement désalloué. Le problème est que les weakréférences à lui sont déjà annulées! La propriété delegateWeakcontient nil, mais delegateAssigncontient un objet valide (avec toutes les propriétés déjà publiées et annulées, mais toujours valides).

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething]; // Does nothing, already nil.
    [delegateAssign doSomething]; // Successful call.
}

C'est un cas assez spécial, mais il nous révèle comment ces weakvariables fonctionnent et quand elles sont annulées.

Tricertops
la source
20

Le document de Clang sur l' Objective-C Automatic Reference Counting (ARC) explique clairement les qualificatifs et modificateurs de propriété:

Il existe quatre critères de propriété:

  • __ autoreleasing
  • __ fort
  • __ * unsafe_unretained *
  • __ faible

Un type ne possède pas de propriété exclusive s'il est qualifié de __ autoreleasing , __ strong ou __ faible .

Ensuite, il existe six modificateurs de propriété pour la propriété déclarée:

  • assign implique la propriété __ * unsafe_unretained *.
  • la copie implique une propriété forte de __ , ainsi que le comportement habituel de la sémantique de copie sur le setter.
  • conserver implique __ une forte propriété.
  • fort implique __ une forte propriété.
  • * unsafe_unretained * implique la propriété __ * unsafe_unretained *.
  • faible implique une faible propriété.

À l'exception des faibles , ces modificateurs sont disponibles en modes non ARC.

Sémantiquement, les qualificatifs de propriété ont une signification différente dans les cinq opérations gérées : lecture, affectation, initialisation, destruction et déplacement, dans lesquelles la plupart du temps, nous ne nous soucions que de la différence dans l'opération d'affectation.

L'affectation se produit lors de l'évaluation d'un opérateur d'affectation. La sémantique varie en fonction de la qualification:

  • Pour __ objets forts , la nouvelle pointe est d'abord conservée; deuxièmement, la valeur l est chargée de sémantique primitive; troisièmement, la nouvelle pointee est stockée dans la valeur l avec une sémantique primitive; et enfin, la vieille pointee est libérée. Cela n'est pas effectué de manière atomique; une synchronisation externe doit être utilisée pour garantir la sécurité face aux charges et aux stockages simultanés.
  • Pour __ objets faibles , la valeur l est mise à jour pour pointer vers la nouvelle pointe, à moins que la nouvelle pointe ne soit un objet en cours de désallocation, auquel cas la valeur l est mise à jour vers un pointeur nul. Cela doit s'exécuter atomiquement par rapport aux autres affectations à l'objet, aux lectures de l'objet et à la version finale de la nouvelle pointee.
  • Pour les objets __ * unsafe_unretained *, la nouvelle pointee est stockée dans la valeur l à l'aide de la sémantique primitive.
  • Pour __ objets autoreleasing , la nouvelle pointee est conservée, autoreleased et stockée dans la valeur l à l'aide d'une sémantique primitive.

L'autre différence dans Reading, Init, Destruction et Moving, veuillez vous référer à la section 4.2 Sémantique du document .

Mingming
la source
6

Pour comprendre la référence forte et faible, considérons l'exemple ci-dessous, supposons que nous ayons une méthode nommée displayLocalVariable.

 -(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
  }

Dans la méthode ci-dessus, la portée de la variable myName est limitée à la méthode displayLocalVariable, une fois que la méthode est terminée, la variable myName qui contient la chaîne "ABC" sera désallouée de la mémoire.

Maintenant, que faire si nous voulons conserver la valeur de la variable myName tout au long de notre cycle de vie du contrôleur de vue. Pour cela, nous pouvons créer la propriété nommée comme nom d'utilisateur qui aura une référence forte à la variable myName (voir self.username = myName;dans le code ci-dessous), comme ci-dessous,

@interface LoginViewController ()

@property(nonatomic,strong) NSString* username;
@property(nonatomic,weak) NSString* dummyName;

- (void)displayLocalVariable;

@end

@implementation LoginViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

}

-(void)viewWillAppear:(BOOL)animated
{
     [self displayLocalVariable];
}

- (void)displayLocalVariable
{
   NSString myName = @"ABC";
   NSLog(@"My name is = %@", myName);
   self.username = myName;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


@end

Maintenant, dans le code ci-dessus, vous pouvez voir que myName a été attribué à self.username et self.username a une référence forte (comme nous l'avons déclaré dans l'interface en utilisant @property) à myName (indirectement, il a une référence forte à la chaîne "ABC"). Par conséquent, String myName ne sera pas désalloué de la mémoire tant que self.username n'est pas vivant.

  • Référence faible

Envisagez maintenant d'affecter myName à dummyName qui est une référence faible, self.dummyName = myName; Contrairement à la référence forte, la valeur faible ne contiendra le nom que jusqu'à ce qu'il y ait une référence forte à mon nom. Voir le code ci-dessous pour comprendre la référence faible,

-(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
     self.dummyName = myName;
  }

Dans le code ci-dessus, il y a une référence faible à myName (c'est-à-dire que self.dummyName a une référence faible à myName) mais il n'y a pas de référence forte à myName, donc self.dummyName ne pourra pas contenir la valeur myName.

Maintenant, considérez à nouveau le code ci-dessous,

-(void)displayLocalVariable
      {
         NSString myName = @"ABC";
         NSLog(@"My name is = %@", myName);
         self.username = myName;
         self.dummyName = myName;
      } 

Dans le code ci-dessus, self.username a une référence forte à myName, donc self.dummyName aura désormais une valeur de myName même après la fin de la méthode, car myName a une référence Strong associée.

Maintenant, chaque fois que nous faisons une référence forte à une variable, son nombre de retenues est augmenté de un et la variable n'obtiendra pas le nombre de retenues désallouées atteignant 0.

J'espère que cela t'aides.

Mahadev Mandale
la source
2

Fort:

  • La propriété ne sera pas détruite mais ce n'est qu'une fois que vous aurez défini la propriété sur zéro que l'objet sera détruit
  • Par défaut, toutes les variables d'instance et les variables locales sont des pointeurs puissants.
  • Vous utilisez fort uniquement si vous devez conserver l'objet.
  • Nous utilisons généralement Strong pour UIViewControllers (les parents de l'élément d'interface utilisateur)
  • IOS 4 (non-ARC), nous pouvons utiliser Retain KeyWord
  • IOS 5 (ARC), nous pouvons utiliser des mots clés forts

Exemple: @property (strong, nonatomic) ViewController * viewController;

@synthesize viewController;

Faible

Par défaut, obtient et définit automatiquement nil

  • Nous utilisons généralement faible pour IBOutlets (UIViewController Childs) et délégué
  • la même chose que l'attribution, aucune conservation ou libération

Exemple: @property (faible, non anatomique) IBOutlet UIButton * myButton;

@synthesize myButton;

Nikunj Patel
la source
1

Les différences entre fort et retenir:

  • Dans iOS4, fort est égal à conserver
  • Cela signifie que vous possédez l'objet et le conservez dans le tas jusqu'à ce que vous ne le montriez plus
  • Si vous écrivez conserver, cela fonctionnera automatiquement comme fort

Les différences entre faible et assigné:

  • Une référence «faible» est une référence que vous ne conservez pas et vous la conservez tant que quelqu'un d'autre la pointe fortement
  • Lorsque l'objet est «désalloué», le pointeur faible est automatiquement réglé sur zéro
  • Un attribut de propriété "assign" indique au compilateur comment synthétiser l'implémentation du setter de la propriété
Chen Rui
la source