ARC-obiettivo-C: forte contro mantenimento e debole contro assegnazione


367

Esistono due nuovi attributi di gestione della memoria per le proprietà introdotte da ARC stronge weak.

A parte copy, che è ovviamente qualcosa di completamente diverso, ci sono differenze tra strongvs retaine weakvs assign?

Da quanto ho capito, l'unica differenza qui è che weakverrà assegnato nilal puntatore, mentre assignnon lo farà, il che significa che il programma andrà in crash quando invio un messaggio al puntatore una volta rilasciato. Ma se lo uso weak, questo non accadrà mai, perché il messaggio inviato a nilnon farà nulla.

Non conosco differenze tra stronge retain.

C'è qualche motivo per cui dovrei usare assigne retainin nuovi progetti, o sono il tipo di deprecato?


12
Ci sono tre nuovi attributi di gestione della memoria per le proprietà introdotte da ARC strong, weake unsafe_unretained.
NJones,

5
@NJones Ci sono due attributi di proprietà ( weake strong) e 4 di qualificazione di durata variabile ( __strong, __weak, __unsafe_unretained, __autoreleasing). Vedi le note ARC di seguito.
Snowcrash,

1
@SnowCrash Esisteva una versione di Xcode, probabilmente un'anteprima dello sviluppatore, in cui l'utilizzo assigndurante la compilazione con ARC era un errore. Ci sono molte risposte cancellate su questo. Sembra che sia stato modificato prima della versione finale. unsafe_unretainedè l'attributo preferito per molti di noi primi utenti. Per la prova che unsafe_unretainedè un attributo valido, guarda la "Programmazione con Objective-C" di Apple nella sezione "Incapsulamento dei dati" sotto il sottotitolo "Usa riferimenti non mantenuti non sicuri per alcune classi". Che dice: "Per una proprietà, questo significa usare l'attributo unsafe_unretained:"
NJones,

Risposte:


230

Dalle note sulla versione Transitioning to ARC (l'esempio nella sezione relativa agli attributi delle proprietà).

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

@property(strong) MyClass *myObject;

Così strongè lo stesso che retainin una dichiarazione di proprietà.

Per i progetti ARC che userei stronginvece di retain, userei assignper le proprietà primitive in C e weakper i riferimenti deboli agli oggetti Objective-C.


11
In effetti, sotto ARC è un errore di compilazione da usare assignper un oggetto. Devi usare uno weako unsafe_unretained(che non è sicuro, ovviamente) se non vuoi conservare la proprietà.
cobbal

5
assigncompila bene per me nei progetti ARC con target di distribuzione 4.0.
Pascal,

8
@Pascal: i riferimenti deboli non sono consentiti nelle destinazioni di distribuzione in cui il sistema operativo non è 5.0 o superiore. Quindi, per i progetti più vecchi, puoi ancora utilizzare Assegna, ma se passi a versioni più recenti devi passare a debole
Mattia

1
Sembra che Xcode 4 (con ARC) generi sottoclassi NSManagedObject usando retainvs strong.. Suppongo che sia per lo più innocuo, ma immagino che dovrebbe essere strongper coerenza ... o forse non importa. stackoverflow.com/questions/7796476/…
Joe D'Andrea,

3
@JeremyP Sì, la tua risposta è precisa. Stavo reagendo a @Mattia. Stavo sottolineando che assignè ancora valido in alcuni casi.
Steven Oxley,

606

Dopo aver letto tanti articoli su Stackoverflow e applicazioni demo per controllare gli attributi delle proprietà variabili, ho deciso di mettere insieme tutte le informazioni sugli attributi:

  1. atomic // default
  2. nonatomic
  3. strong = keep // default
  4. debole
  5. conservare
  6. assegnare // predefinito
  7. unsafe_unretained
  8. copia
  9. sola lettura
  10. readwrite // default

Di seguito è riportato il link dettagliato dell'articolo in cui puoi trovare tutti gli attributi sopra menzionati, che ti aiuteranno sicuramente. Mille grazie a tutte le persone che danno le migliori risposte qui !!

Attributi di proprietà variabili o modificatori in iOS

1.strong (iOS4 = conserva)

  • dice "tienilo nell'heap fino a quando non lo indico più"
  • in altre parole "Sono il proprietario, non puoi dislocare prima di mirare bene con lo stesso di"
  • Si usa forte solo se è necessario conservare l'oggetto.
  • Per impostazione predefinita, tutte le variabili di istanza e le variabili locali sono puntatori forti.
  • Generalmente utilizziamo strong per UIViewController (genitori dell'elemento UI)
  • strong è usato con ARC e ti aiuta sostanzialmente, non dovendo preoccuparti del conteggio degli oggetti. ARC lo rilascia automaticamente per te quando hai finito con esso. L'uso della parola chiave strong significa che sei il proprietario dell'oggetto.

Esempio:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2. debole -

  • dice "mantieni questo fintanto che qualcun altro lo indica con forza"
  • la stessa cosa di assegnare, non conservare o rilasciare
  • Un riferimento "debole" è un riferimento che non si conserva.
  • Generalmente usiamo debole per IBOutlets (Childs di UIViewController). Questo funziona perché l'oggetto child deve esistere solo finché lo fa l'oggetto genitore.
  • un riferimento debole è un riferimento che non protegge l'oggetto referenziato dalla raccolta da parte di un garbage collector.
  • Debole è essenzialmente assegnare, una proprietà non mantenuta. Tranne quando l'oggetto è deallocato, il puntatore debole viene automaticamente impostato su zero

Esempio :

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

@synthesize myButton;

Spiegazione forte e debole, grazie a BJ Homer :

Immagina che il nostro oggetto sia un cane e che il cane voglia scappare (essere deallocato).

Puntatori forti sono come un guinzaglio per il cane. Finché hai il guinzaglio attaccato al cane, il cane non scapperà. Se cinque persone attaccano il loro guinzaglio a un cane (cinque forti puntatori a un oggetto), il cane non scapperà finché tutti e cinque i guinzagli non saranno staccati.

Indicatori deboli, d'altra parte, sono come bambini piccoli che indicano il cane e dicono "Guarda! Un cane!" Finché il cane è ancora al guinzaglio, i bambini piccoli possono ancora vedere il cane e lo indicheranno comunque. Non appena tutti i guinzagli vengono staccati, tuttavia, il cane scappa, indipendentemente da quanti bambini lo indicano.

Non appena l'ultimo puntatore forte (guinzaglio) non punta più a un oggetto, l'oggetto verrà deallocato e tutti i puntatori deboli verranno azzerati.

Quando usiamo debole?

L'unica volta che vorresti usare un debole, è se volevi evitare i cicli di mantenimento (ad es. Il genitore conserva il figlio e il bambino conserva il genitore, quindi nessuno dei due viene mai rilasciato).

3.retain = forte

  • viene mantenuto, il vecchio valore viene rilasciato e assegnato viene assegnato specifica che il nuovo valore deve essere inviato
  • mantenere su assegnazione e il vecchio valore inviato-release
  • trattenere è lo stesso di forte.
  • Apple dice che se scrivi Mantieni verrà automaticamente convertito / funzionerà come se fosse forte.
  • metodi come "alloc" includono un "trattenimento" implicito

Esempio:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4.assign

  • Assegnare è l'impostazione predefinita ed esegue semplicemente un'assegnazione variabile
  • assegnare è un attributo della proprietà che indica al compilatore come sintetizzare l'implementazione del setter della proprietà
  • Userei assegnare per le proprietà primitive C e debole per riferimenti deboli agli oggetti Objective-C.

Esempio:

@property (nonatomic, assign) NSString *address;

@synthesize address;

5
2. "un riferimento debole è un riferimento che non protegge l'oggetto referenziato dalla raccolta da parte di un garbage collector" - non esiste nulla nell'obiettivo c come garbage collector;
Bucherland

1
e questa gerarchia è gestita automaticamente da iOS. Leggi il concetto di MVC. Voglio dire quando ViewContorller viene presentato iOS carica la sua gerarchia di visualizzazioni sullo schermo (creando viste mancanti). Quando viene presentato un altro ViewController, questa prima gerarchia di viste viene deallocata. Ma se hai "forte" in ViewController, allora questa vista non può essere deallocata, quando è fuori schermo. Il che potrebbe avere un forte impatto sulla memoria del dispositivo e la causa del rallentamento dell'app. (Ovviamente il dispositivo ha un sacco di memoria e staresti sicuramente bene con l'app per schermo 5-10, ma in un'app enorme ti
metterai

1
Quando usiamo debole? 1. Per gli oggetti dell'interfaccia utente, 2. delegati, 3. blocchi (deboli Se stessi dovrebbe essere usato al posto di sé per evitare cicli di memoria (come menzionato sopra)
bucherland

1
C'è un errore in questa grande risposta - forte - "ARC lo rilascia automaticamente per te quando hai finito con esso", questo non è giusto. ARC rilascerà automaticamente oggetti deboli quando non ci sono puntatori. Forte - è sinonimo di mantenimento, quindi l'oggetto viene mantenuto ed è nostra responsabilità rendere l'oggetto nullo
Ashwin G

1
@RDC, cosa defaultsignifica? Se lo uso @property (nonatomic) NSString *stringlo è strong? Oppure assign? Perché entrambi sono valori predefiniti.
Iulian Onofrei il

40

nonatomic / atomica

  • il nonatomico è molto più veloce dell'atomico
  • usa sempre nonatomico a meno che tu non abbia un requisito molto specifico per atomico, che dovrebbe essere raro (atomico non garantisce la sicurezza del thread - le bancarelle accedono alla proprietà solo quando è impostato contemporaneamente da un altro thread)

forte / debole / assegnare

  • usa strong per conservare gli oggetti - anche se la parola chiave keep è sinonimo, è meglio usare strong invece
  • usa debole se vuoi solo un puntatore all'oggetto senza trattenerlo - utile per evitare cicli di trattenimento (es. delegati) - annulla automaticamente il puntatore quando viene rilasciato l'oggetto
  • usa Assegna per primitive - esattamente come debole tranne che non azzera l'oggetto quando viene rilasciato (impostato di default)

(Opzionale)

copia

  • usalo per creare una copia superficiale dell'oggetto
  • buona pratica per impostare sempre le proprietà immutabili da copiare - poiché le versioni mutabili possono essere passate in proprietà immutabili, la copia assicurerà che avrai sempre a che fare con un oggetto immutabile
  • se un oggetto immutabile viene passato, lo manterrà - se viene passato un oggetto mutabile, lo copierà

sola lettura

  • usalo per disabilitare l'impostazione della proprietà (impedisce la compilazione del codice in caso di infrazione)
  • puoi cambiare ciò che viene fornito dal getter modificando la variabile direttamente tramite la sua variabile di istanza o all'interno del metodo getter stesso

@Sakthimuthiah ha ragione, devi correggere la tua risposta.
Adela Toderici,

@Sakthimuthiah non è corretto (e chiunque altro lo dica). Atomic NON lo rende thread sicuro, anche se può essere facilmente confuso a causa del suo comportamento. Si prega di leggere: stackoverflow.com/questions/12347236/…
Chris J,

39

Per quanto ne so, stronge retainsono sinonimi, quindi fanno esattamente lo stesso.

Quindi weakè quasi come assign, ma automaticamente impostato a zero dopo che l'oggetto, a cui punta, viene deallocato.

Ciò significa che puoi semplicemente sostituirli.

Tuttavia , c'è un caso speciale che ho riscontrato, in cui ho dovuto usare assign, piuttosto che weak. Diciamo che abbiamo due proprietà delegateAssigne delegateWeak. In entrambi è archiviato il nostro delegato, che ci possiede possedendo l'unico riferimento forte. Il delegato sta deallocando, quindi -deallocviene chiamato anche il nostro metodo.

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

Il delegato è già in fase di deallocazione, ma non è ancora completamente deallocato. Il problema è che i weakriferimenti a lui sono già annullati! La proprietà delegateWeakcontiene zero, ma delegateAssigncontiene un oggetto valido (con tutte le proprietà già rilasciate e annullate, ma comunque valide).

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

È un caso abbastanza speciale, ma ci rivela come funzionano queste weakvariabili e quando vengono annullate.



20

Il documento di Clang sul conteggio dei riferimenti automatici Objective-C (ARC) spiega chiaramente i qualificatori e i modificatori della proprietà:

Esistono quattro qualificatori di proprietà:

  • __ autoreleasing
  • __ forte
  • __ * unsafe_unretained *
  • __ debole

Un tipo è qualificato in modo non proprietario se è qualificato con __ autoreleasing , __ strong o __ debole .

Quindi ci sono sei modificatori di proprietà per la proprietà dichiarata:

  • assegnare implica __ * unsafe_unretained * proprietà.
  • copia implica __ forte proprietà, così come il solito comportamento della semantica della copia sul setter.
  • mantenere implica __ forte proprietà.
  • forte implica __ forte proprietà.
  • * unsafe_unretained * implica __ * unsafe_unretained * proprietà.
  • debole implica __ debole proprietà.

Ad eccezione di quelli deboli , questi modificatori sono disponibili in modalità non ARC.

Per quanto riguarda la semantica, i qualificatori della proprietà hanno un significato diverso nelle cinque operazioni gestite : Lettura, Assegnazione, Inizializzazione, Distruzione e Trasloco, in cui la maggior parte delle volte ci interessa solo la differenza nell'operazione di assegnazione.

L'assegnazione si verifica durante la valutazione di un operatore di assegnazione. La semantica varia in base alla qualifica:

  • Per __ oggetti forti , la nuova punta viene prima mantenuta; secondo, il lvalue viene caricato con semantica primitiva; terzo, la nuova punta viene memorizzata nel valore con semantica primitiva; e infine, la vecchia punta viene rilasciata. Questo non viene eseguito atomicamente; la sincronizzazione esterna deve essere utilizzata per renderlo sicuro di fronte a carichi e archivi simultanei.
  • Per __ oggetti deboli , il lvalue viene aggiornato in modo da puntare alla nuova punta, a meno che la nuova punta sia un oggetto attualmente sottoposto a deallocazione, nel qual caso il lvalue viene aggiornato con un puntatore nullo. Questo deve essere eseguito atomicamente rispetto ad altre assegnazioni all'oggetto, alle letture dell'oggetto e alla versione finale della nuova punta.
  • Per oggetti __ * unsafe_unretained *, la nuova punta viene memorizzata nel valore usando la semantica primitiva.
  • Per __ oggetti con rilascio automatico , la nuova punta viene mantenuta, rilasciata automaticamente e memorizzata nel valore usando la semantica primitiva.

L'altra differenza in Lettura, Init, Distruzione e Spostamento, fare riferimento alla Sezione 4.2 Semantica nel documento .


6

Per capire il riferimento forte e debole, considera l'esempio seguente, supponiamo di avere un metodo chiamato displayLocalVariable.

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

Nell'ambito del metodo precedente la variabile myName è limitata al metodo displayLocalVariable, una volta terminato il metodo la variabile myName che contiene la stringa "ABC" verrà deallocata dalla memoria.

Ora, se vogliamo mantenere il valore della variabile myName per tutto il ciclo di vita del controller di visualizzazione. Per questo possiamo creare la proprietà denominata come nome utente che avrà un forte riferimento alla variabile myName (vedere self.username = myName;nel codice seguente), come di seguito,

@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

Ora nel codice sopra puoi vedere myName è stato assegnato a self.username e self.username sta avendo un forte riferimento (come abbiamo dichiarato nell'interfaccia usando @property) a myName (indirettamente ha un forte riferimento alla stringa "ABC"). Quindi String myName non verrà deallocato dalla memoria fino a quando self.username non è attivo.

  • Riferimento debole

Ora considera di assegnare myName a dummyName che è un riferimento debole, self.dummyName = myName; A differenza del riferimento forte, Weak manterrà myName solo fino a quando non ci sarà un riferimento forte a myName. Vedi sotto il codice per capire il riferimento debole,

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

Nel codice sopra c'è un riferimento debole a myName (cioè self.dummyName ha un riferimento debole a myName) ma non c'è un riferimento forte a myName, quindi self.dummyName non sarà in grado di contenere il valore myName.

Ora considera di nuovo il codice seguente,

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

Nel codice sopra self.username ha un riferimento forte a myName, quindi self.dummyName ora avrà un valore di myName anche dopo la fine del metodo poiché a myName è associato un riferimento forte.

Ora, ogni volta che facciamo un riferimento forte a una variabile, il suo conteggio dei trattenuti viene aumentato di uno e la variabile non viene distribuita. Il conteggio dei trattenuti arriva a 0.

Spero che sia di aiuto.


2

Forte:

  • La proprietà non distruggerà ma solo una volta impostata la proprietà su zero l'oggetto verrà distrutto
  • Per impostazione predefinita, tutte le variabili di istanza e le variabili locali sono puntatori forti.
  • Si usa forte solo se è necessario conservare l'oggetto.
  • Generalmente utilizziamo strong per UIViewController (genitori dell'elemento UI)
  • IOS 4 (non ARC) Possiamo usare Mantieni KeyWord
  • IOS 5 (ARC) Possiamo usare parole chiave efficaci

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

@synthesize viewController;

Debole

Per impostazione predefinita, ottieni automaticamente e impostato su zero

  • In genere utilizziamo i punti deboli per IBOutlet (Childs di UIViewController) e delegati
  • la stessa cosa di assegnare, non conservare o rilasciare

Esempio: @property (debole, non anatomico) IBOutlet UIButton * myButton;

@synthesize myButton;


1

Le differenze tra forte e mantenere:

  • In iOS4, strong è uguale a mantenere
  • Significa che possiedi l'oggetto e tienilo nell'heap fino a quando non lo punti più
  • Se scrivi keep funzionerà automaticamente proprio come se fosse forte

Le differenze tra debolezza e assegnazione:

  • Un riferimento "debole" è un riferimento che non si conserva e lo si mantiene finché qualcun altro lo indica con forza
  • Quando l'oggetto viene "deallocato", il puntatore debole viene automaticamente impostato su zero
  • Un attributo della proprietà "Assegna" indica al compilatore come sintetizzare l'implementazione del setter della proprietà
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.