web-dev-qa-db-fra.com

Objective-C ARC: fort vs retenu et faible vs assigné

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

Mis à part copy, qui est évidemment quelque chose de complètement différent, existe-t-il des différences entre strong et retain et weak et assign? =

A ma connaissance, la seule différence est que weak assignera nil au pointeur, tandis que assign ne le fera pas, ce qui signifie que le programme se bloquera lorsque j'enverrai un message au pointeur. une fois qu'il est sorti. Mais si j'utilise weak, cela n'arrivera jamais, car le message envoyé à nil ne fera rien.

Je ne connais aucune différence entre strong et retain.

Y a-t-il une raison pour laquelle je devrais utiliser assign et retain dans de nouveaux projets, ou le type de celui-ci est-il déconseillé?

361
Jakub Arnold

À partir de Notes de publication du passage à ARC (exemple dans la section sur les attributs de propriété).

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

@property(strong) MyClass *myObject;

Donc, strong est identique à retain dans une déclaration de propriété.

Pour les projets ARC, j’utiliserais strong au lieu de retain, j’utiliserais assign pour les propriétés primitives C et weak pour les références faibles à des objets Objective-C.

228
JeremyP

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

  1. atomique // par défaut
  2. non atomique
  3. fort = conserver // par défaut
  4. faible
  5. conserver
  6. assign // valeur 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é de variable ou modificateurs sous iOS

1.strong (iOS4 = conserver)

  • il dit "gardez cela dans le tas jusqu'à ce que je ne pointe plus dessus"
  • en d'autres termes "je suis le propriétaire, vous ne pouvez pas désaffecter cela avant de viser très bien avec ce 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 indicateurs puissants.
  • Nous utilisons généralement fort pour UIViewControllers (les parents de l'élément de l'interface utilisateur)
  • strong est utilisé avec ARC et vous aide fondamentalement à ne pas avoir à vous soucier du nombre de retenues d'un objet. ARC le publie automatiquement pour vous lorsque vous avez terminé. Le mot-clé strong signifie que vous êtes propriétaire de l'objet.

Exemple:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2.weak -

  • il dit "gardez ceci aussi longtemps que quelqu'un d'autre pointe dessus"
  • la même chose que assigner, pas retenir ou libérer
  • Une référence "faible" est une référence que vous ne conservez pas.
  • Nous utilisons généralement faible pour IBOutlets (UIViewController's Childs). Cela fonctionne car l'objet enfant n'a besoin d'exister que tant que l'objet parent existe.
  • 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 ramasse-miettes.
  • Faible est essentiellement assigner, une propriété non conservée. Sauf que lorsque l'objet est désalloué, le pointeur faible est automatiquement défini sur nil

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 celui-ci veuille fuir (être désalloué).

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

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

Dès que le dernier pointeur fort (leash) ne pointe plus vers un objet, celui-ci est désalloué et tous les pointeurs faibles sont mis à zéro.

Quand on utilise faible?

Si vous souhaitez éviter les cycles de rétention (par exemple, le parent conserve l’enfant et l’enfant le conserve, le parent n’est jamais relâché).

3.retain = strong

  • elle est conservée, l'ancienne valeur est publiée et elle est affectée à conserver indique que la nouvelle valeur doit être envoyée
  • conserver en cession et l'ancienne valeur envoyée - libération
  • retenir est le même que fort.
  • Apple dit que si vous écrivez à conserver, il sera automatiquement converti/fonctionnera comme si c'était uniquement fort.
  • des méthodes telles que "alloc" incluent un implicite "conserver"

Exemple:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4.assign

  • 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 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;
600
swiftBoy

Autant que je sache, strong et retain sont des synonymes, donc ils font exactement la même chose.

Ensuite, la weak est presque semblable à assign, mais elle est automatiquement définie sur nil après que l'objet sur lequel il pointe est désalloué.

Cela signifie que vous pouvez simplement les remplacer.

Cependant, j'ai rencontré un cas spécial dans lequel je devais utiliser assign plutôt que weak. Disons que nous avons deux propriétés delegateAssign et delegateWeak. Dans les deux cas est stocké notre délégué, c'est-à-dire nous posséder en ayant la seule référence forte. Le délégué désalloue alors notre méthode -dealloc est également appelée.

// 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 cours de désallocation, mais n'est pas encore complètement désalloué. Le problème est que weak ses références sont déjà annulées! La propriété delegateWeak contient nil, mais delegateAssign contient un objet valide (avec toutes les propriétés déjà publiées et annulées, mais toujours valable).

// 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 particulier, mais il nous révèle comment fonctionnent ces variables weak et quand elles sont annulées.

39
Tricertops

non atomique/atomique

  • nonatomic est beaucoup plus rapide que l'atome
  • utilisez toujours non atomic, 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; seul un blocage de l'accès à la propriété lorsqu'il est simultanément défini par un autre thread)

fort/faible/assigner

  • utilisez strong pour conserver des objets - bien que le mot clé retenue soit synonyme, il vaut mieux utiliser fort à la place
  • utilisez faible si vous voulez seulement un pointeur sur l'objet sans le conserver - utile pour éviter les cycles de rétention (c'est-à-dire les délégués) - cela éliminera automatiquement le pointeur quand l'objet est libéré
  • utiliser assigner pour les primatives - exactement comme faible, sauf que l'objet n'est pas supprimé lorsque libéré (défini par défaut)

(Optionnel)

copie

  • utilisez-le pour créer une copie superficielle de l'objet
  • une bonne pratique consiste à toujours définir les propriétés immuables sur la copie. Les versions mutables pouvant être passées en propriétés immuables, la copie garantit que vous aurez toujours affaire à un objet immuable.
  • si un objet immuable est passé, il le conservera - si un objet mutable est passé, il le copiera

en lecture seule

  • utilisez-le pour désactiver le paramétrage de la propriété (empêche la compilation du code 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 de getter elle-même
38
Vadoff

Le document de Clang sur Comptage de référence automatique Objective-C (ARC) explique clairement les qualificateurs et modificateurs de propriété:

Il existe quatre qualificateurs de propriété:

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

Un type est qualifié de droit de propriété non indifférent s'il est qualifié avec __ autoreleasing , __ strong ou __ faible.

Il existe ensuite six modificateurs de propriété pour la propriété déclarée:

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

À l'exception de faible , ces modificateurs sont disponibles en mode non ARC.

Du point de vue de la sémantique, les qualificateurs de propriété ont une signification différente dans les cinq opérations gérées : lecture, affectation, initialisation, destruction et déplacement, dans lesquels la plupart du temps se soucient de la différence dans l'opération d'assignation.

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

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

L'autre différence entre Lecture, Init, Destruction et Déménagement, veuillez vous référer à Section 4.2 Sémantique dans le document .

20
Mingming

Pour comprendre les références 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 la méthode terminée, la variable myName contenant la chaîne "ABC" sera libérée de la mémoire.

Et maintenant, si nous voulons conserver la valeur de la variable myName tout au long du cycle de vie de notre contrôleur de vue. Pour cela, nous pouvons créer la propriété nommée username 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é assigné à self.username et que 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'aura pas été activé.

  • Référence faible

Maintenant, envisagez d'affecter myName à dummyName, qui est une référence faible, self.dummyName = myName; Contrairement à la référence forte, le nom de la base sera maintenu par myo uniquement jusqu'à ce qu'il y ait une référence forte à myName. Voir ci-dessous le code 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. Par conséquent, self.dummyName aura désormais la valeur myName, même après la fin de la méthode, car myName est associé à une référence Strong.

Désormais, chaque fois que nous faisons une référence forte à une variable, son nombre de rétention est augmenté de un et la variable ne sera pas désaffectée. Le nombre de rétention atteint 0.

J'espère que cela t'aides.

4
Mahadev Mandale

Fort:

  • La propriété ne sera pas détruite mais l'objet ne sera détruit que lorsque vous définissez la propriété sur nil.
  • Par défaut, toutes les variables d'instance et les variables locales sont des indicateurs puissants.
  • Vous utilisez fort uniquement si vous devez conserver l'objet.
  • Nous utilisons généralement fort pour UIViewControllers (les parents de l'élément de l'interface utilisateur)
  • IOS 4 (non-ARC), nous pouvons utiliser Retain KeyWord
  • IOS 5(ARC) Nous pouvons utiliser un mot clé puissant

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

@synthesize viewController;

Faible

Par défaut, obtenez automatiquement et mettez à zéro

  • Nous utilisons généralement faible pour IBOutlets (UIViewController's Childs) et déléguer
  • la même chose que assigner, pas retenir ou libérer

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

@synthèse myButton;

2
Nikunj Patel

Les différences entre fort et retenir:

  • Dans iOS4, fort est égal à conserver
  • Cela signifie que vous possédez l’objet et le gardez dans le tas jusqu’à ce que vous ne le dirigiez plus.
  • Si vous écrivez conserver, il fonctionnera automatiquement comme un puissant

Les différences entre faible et assigner:

  • Une référence "faible" est une référence que vous ne conservez pas et que vous conservez aussi longtemps que quelqu'un le pointe fortement.
  • Lorsque l'objet est "désalloué", le pointeur faible est automatiquement défini sur nil
  • Un attribut de propriété "assign" indique au compilateur comment synthétiser l'implémentation de la propriété
1
Chen Rui