@property conserva, assegna, copia, non anatomico in Objective-C


214

Come qualcuno che è nuovo in Objective-C qualcuno può darmi una panoramica del mantenimento, assegnare, copiare e tutti gli altri che mi mancano, che seguono la direttiva @property? Cosa stanno facendo e perché dovrei usarne uno sopra l'altro?


1
Il nome di Apple per questi è "attributi" o "attributi di proprietà"
re nevan

Risposte:


274

L'articolo collegato da MrMage non funziona più. Quindi, ecco cosa ho imparato nel mio (molto) breve periodo di programmazione in Objective-C:

nonatomico vs. atomico: "atomico" è l'impostazione predefinita. Utilizzare sempre "non anatomico". Non so perché, ma il libro che ho letto diceva che "raramente c'è una ragione" per usare "atomico". (A proposito: il libro che ho letto è il libro "Programmazione iOS" del BNR.)

readwrite vs. readonly - "readwrite" è l'impostazione predefinita. Quando @synthesize, verranno creati sia un getter che un setter. Se si utilizza "sola lettura", non verrà creato alcun setter. Usalo per un valore che non vuoi mai cambiare dopo l'istanza dell'oggetto.

conserva vs. copia vs. assegna

  • "Assegna" è l'impostazione predefinita. Nel setter creato da @synthesize, il valore verrà semplicemente assegnato all'attributo. La mia comprensione è che "assegnare" dovrebbe essere usato per attributi senza puntatore.
  • "trattenere" è necessario quando l'attributo è un puntatore a un oggetto. Il setter generato da @synthesize manterrà (ovvero aggiungerà un conteggio di mantenimento) l'oggetto. Dovrai rilasciare l'oggetto al termine.
  • "copia" è necessario quando l'oggetto è mutabile. Usalo se hai bisogno del valore dell'oggetto così com'è in questo momento e non vuoi che quel valore rifletta le modifiche apportate da altri proprietari dell'oggetto. Dovrai rilasciare l'oggetto al termine perché stai conservando la copia.

@Blamdarot - devo rilasciarlo anche con ARC
Dejell il

10
@Odelya - No. Se rilasci durante l'utilizzo di ARC, credo che otterrai un errore del compilatore.
Blamdarot,

53
"Usa sempre non anatomico" è un cattivo consiglio. Dovresti sapere a cosa ti stai arrendendo quando usi il nonatomico.
Jesse Rusak,

7
Concordato. In particolare, molte persone non sembrano sapere che i valori non anatomici non vengano rilasciati automaticamente dal getter. nonatomico è spesso appropriato, ma raramente lo è la programmazione di culto del carico.
Catfish_Man

9
Consigliare di lasciare il valore predefinito atomicè altrettanto male che avvisare nonatomic. Nessuna delle due scelte è quella "corretta", quindi i progettisti del linguaggio hanno optato per la più sicura delle due soluzioni. In realtà nonatomicè generalmente la scelta migliore in quanto omette blocchi di thread estremamente costosi. L'unico motivo da utilizzare atomicè se la tua proprietà potrebbe essere impostata da più thread (nel qual caso ometterla può portare a un rilascio eccessivo o una perdita).
Adam Kaplan,

295

Prima di conoscere gli attributi di @property, dovresti sapere a che serve @property.

  • @property offre un modo per definire le informazioni che una classe intende incapsulare. Se dichiari un oggetto / variabile usando @property , quell'oggetto / variabile sarà accessibile ad altre classi importando la sua classe.

  • Se si dichiara un oggetto utilizzando @property nel file di intestazione, è necessario sintetizzarlo utilizzando @synthesize nel file di implementazione. Questo rende l'oggetto conforme a KVC . Per impostazione predefinita, il compilatore sintetizza i metodi di accesso per questo oggetto.

  • i metodi di accesso sono: setter e getter.

Esempio: .h

@interface XYZClass : NSObject
@property (nonatomic, retain) NSString *name;
@end

.m

@implementation XYZClass
@synthesize name;
@end

Ora il compilatore sintetizzerà i metodi accessor per nome .

XYZClass *obj=[[XYZClass alloc]init];
NSString *name1=[obj name]; // get 'name'
[obj setName:@"liza"]; // first letter of 'name' becomes capital in setter method
  • Elenco di attributi di @property

    atomico, non anatomico, conserva, copia, sola lettura, lettura / scrittura, assegnazione, forte, getter = metodo, setter = metodo, non sicuro_unretained

  • atomic è il comportamento predefinito. Se un oggetto viene dichiarato atomico, diventa thread-safe. Thread-safe significa che alla volta solo un thread di una particolare istanza di quella classe può avere il controllo su quell'oggetto.

Se il thread sta eseguendo il metodo getter, l'altro thread non può eseguire il metodo setter su quell'oggetto. È lento.

@property NSString *name; //by default atomic`
@property (atomic)NSString *name; // explicitly declared atomic`
  • nonatomic non è thread-safe. È possibile utilizzare l'attributo della proprietà nonatomica per specificare che gli accessori sintetizzati semplicemente impostano o restituiscono un valore direttamente, senza garanzie su ciò che accade se si accede allo stesso valore simultaneamente da thread diversi.

Per questo motivo, è più veloce accedere a una proprietà non anatomica rispetto a una atomica.

@property (nonatomic)NSString *name;   
  • la conservazione è richiesta quando l'attributo è un puntatore a un oggetto.

Il metodo setter aumenterà il conteggio degli oggetti, in modo che occupi memoria nel pool di autorelease.

@property (retain)NSString *name;
  • copia Se si utilizza la copia, non è possibile utilizzare la conservazione. L'uso dell'istanza di copia della classe conterrà la propria copia.

Anche se viene impostata e successivamente modificata una stringa mutabile, l'istanza acquisisce qualsiasi valore abbia al momento dell'impostazione. Non saranno sintetizzati metodi setter e getter.

@property (copy) NSString *name;

adesso,

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"]; 

il nome rimarrà inalterato.

  • di sola lettura Se non si desidera consentire la modifica della proprietà tramite il metodo setter, è possibile dichiarare la proprietà in sola lettura.

Il compilatore genererà un getter, ma non un setter.

@property (readonly) NSString *name;
  • readwrite è il comportamento predefinito. Non è necessario specificare l'attributo readwrite in modo esplicito.

È l'opposto di sola lettura.

@property (readwrite) NSString *name;
  • assegnare genererà un setter che assegna direttamente il valore alla variabile di istanza, anziché copiarlo o conservarlo. Questo è il migliore per tipi primitivi come NSInteger e CGFloat, o oggetti che non possiedi direttamente, come i delegati.

Ricorda che conservare e assegnare sono sostanzialmente intercambiabili quando è abilitata la raccolta dei rifiuti.

@property (assign) NSInteger year;
  • forte è un sostituto per ritenere.

Viene fornito con ARC.

@property (nonatomic, strong) AVPlayer *player; 
  • getter = method Se si desidera utilizzare un nome diverso per un metodo getter, è possibile specificare un nome personalizzato aggiungendo attributi alla proprietà.

Nel caso delle proprietà booleane (proprietà che hanno un valore SÌ o NO), è consuetudine che il metodo getter inizi con la parola "is"

@property (getter=isFinished) BOOL finished;
  • setter = method Se si desidera utilizzare un nome diverso per un metodo setter, è possibile specificare un nome personalizzato aggiungendo attributi alla proprietà.

Il metodo dovrebbe terminare con due punti.

@property(setter = boolBool:) BOOL finished;
  • unsafe_unretained Esistono alcune classi in Cocoa e Cocoa Touch che non supportano ancora riferimenti deboli, il che significa che non è possibile dichiarare una proprietà debole o una variabile locale debole per tenerne traccia. Queste classi includono NSTextView, NSFont e NSColorSpace, ecc. Se è necessario utilizzare un riferimento debole a una di queste classi, è necessario utilizzare un riferimento non sicuro.

Un riferimento non sicuro è simile a un riferimento debole in quanto non mantiene in vita l'oggetto correlato, ma non sarà impostato su zero se l'oggetto di destinazione è deallocato.

@property (unsafe_unretained) NSObject *unsafeProperty;

Se è necessario specificare più attributi, includerli semplicemente come un elenco separato da virgole, in questo modo:

@property (readonly, getter=isFinished) BOOL finished;

Inoltre, debole significa che non esiste un conteggio dei riferimenti a cui fa riferimento l'oggetto, ma che a cui fa riferimento o che non fa affatto riferimento. Un po 'come "sì, qualcosa mi ha fatto riferimento" vs. "Esistono 9 riferimenti a me" (che è ciò che è forte).
Alex Zavatone,

6
Ignora la riga nella risposta relativa alla garbage collection, poiché la garbage collection è obsoleta in Mac OS X e inesistente nella documentazione iOS per Apple .
Basil Bourque,

4
"Nota: l'atomicità delle proprietà non è sinonimo di sicurezza del thread di un oggetto." - da developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7

1
"Se si dichiara un oggetto utilizzando @propertynel file di intestazione, è necessario sintetizzarlo utilizzando @synthesizenel file di implementazione." Non sempre. Ad esempio, "Per impostazione predefinita, una readwriteproprietà sarà supportata da una variabile di istanza, che verrà nuovamente sintetizzata automaticamente dal compilatore." Dal doc .
Franklin Yu,

4
@liza Questa è una risposta eccellente. Perché questa non è la risposta accettata? Trasmette una spiegazione molto più consapevole della risposta attualmente accettata. Non capisco StackOverflow a volte?
Charles Robertson,

149

Dopo aver letto molti articoli ho deciso di mettere insieme tutte le informazioni sugli attributi:

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

Di seguito è riportato un collegamento all'articolo dettagliato in cui è possibile trovare questi attributi.

Mille grazie a tutte le persone che danno le migliori risposte qui !!

Attributi di proprietà variabili o modificatori in iOS

Ecco la descrizione del campione dall'articolo

  1. atomico- Atomico significa che solo un thread accede alla variabile (tipo statico). -Atomic è thread-safe. -ma è lento nelle prestazioni -L'anatomia è un comportamento predefinito -Gli accessi atomici in un ambiente non immondizia raccolto (cioè quando si utilizza la conservazione / rilascio / rilascio automatico) useranno un blocco per assicurarsi che un altro thread non interferisca con l'impostazione / acquisizione corrette del valore. -non è in realtà una parola chiave.

Esempio :

@property (retain) NSString *name;

@synthesize name;
  1. nonatomico -Nonatomico significa accesso multiplo alla variabile (tipo dinamico). -Nonatomic è thread non sicuro. -ma è veloce nelle prestazioni -Nonatomic NON è un comportamento predefinito, dobbiamo aggiungere una parola chiave nonatomica nell'attributo proprietà. -può provocare comportamenti imprevisti, quando due processi diversi (thread) accedono alla stessa variabile contemporaneamente.

Esempio:

@property (nonatomic, retain) NSString *name;

@synthesize name;

Spiegare:

Supponiamo che esista una proprietà di stringa atomica chiamata "name" e se chiami [self setName: @ "A"] dal thread A, chiami [self setName: @ "B"] dal thread B e chiami [self name] da thread C, quindi tutte le operazioni su thread diversi verranno eseguite in serie, il che significa che se un thread esegue setter o getter, altri thread aspetteranno. Questo rende la proprietà "nome" di lettura / scrittura sicura ma se un altro thread D chiama [rilascio nome] contemporaneamente, questa operazione potrebbe causare un arresto anomalo perché qui non sono coinvolte chiamate setter / getter. Ciò significa che un oggetto è in lettura / scrittura sicuro (ATOMIC) ma non sicuro per i thread poiché un altro thread può inviare contemporaneamente qualsiasi tipo di messaggio all'oggetto. Lo sviluppatore dovrebbe garantire la sicurezza dei thread per tali oggetti.

Se la proprietà "name" non era anatomica, tutti i thread nell'esempio precedente - A, B, C e D eseguiranno simultaneamente producendo risultati imprevedibili. In caso di atomico, uno dei due A, B o C verrà eseguito per primo ma D può ancora essere eseguito in parallelo.

  1. strong (iOS4 = keep) -s dice "tienilo nell'heap fino a quando non lo indico più" -in altre parole "Sono il proprietario, non puoi distribuirlo prima di mirare bene con lo stesso di keep" - Si usa forte solo se è necessario conservare l'oggetto. -Per impostazione predefinita, tutte le variabili di istanza e le variabili locali sono puntatori forti. -Si usa generalmente forte per UIViewControllers (genitori dell'elemento dell'interfaccia utente) -strong viene utilizzato con ARC e ti aiuta sostanzialmente, senza doversi preoccupare 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;
  1. debole (iOS4 = unsafe_unretained) -si 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. -Si usa generalmente debole per IBOutlet (Childs di UIViewController). Questo funziona perché l'oggetto figlio deve esistere solo finché l'oggetto genitore lo fa. -un riferimento debole è un riferimento che non protegge l'oggetto referenziato dalla raccolta da parte di un garbage collector. -Weak è essenzialmente assegnato, una proprietà non mantenuta. Tranne quando l'oggetto viene 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).

  1. retain = strong -it viene mantenuto, il vecchio valore viene rilasciato e assegnato -retain specifica che il nuovo valore deve essere inviato -retain al momento dell'assegnazione e il vecchio valore inviato -release -retain è lo stesso di strong. -apple dice che se scrivi manterrai automaticamente convertito / funzionerà come solo forte. metodi come "alloc" includono un "trattenimento" implicito

Esempio:

@property (nonatomic, retain) NSString *name;

@synthesize name;
  1. Assegnare -assign è il valore predefinito ed esegue semplicemente un'assegnazione variabile -assign è un attributo della proprietà che dice al compilatore come sintetizzare l'implementazione del setter della proprietà -Io userei assegnare per proprietà primitive C e debole per riferimenti deboli a oggetti Objective-C.

Esempio:

@property (nonatomic, assign) NSString *address;

@synthesize address;
  1. unsafe_unretained

    -unsafe_unretained è un qualificatore di proprietà che indica ad ARC come inserire le chiamate di conservazione / rilascio -unsafe_unretained è la versione ARC di assegnazione.

Esempio:

@property (nonatomic, unsafe_unretained) NSString *nickName;

@synthesize nickName;
  1. copia -copy è richiesto quando l'oggetto è mutabile. -copy specifica che il nuovo valore deve essere inviato -copia al momento dell'assegnazione e il vecchio valore inviato -release. -copy è come trattenuta restituisce un oggetto che è necessario rilasciare esplicitamente (ad esempio, in dealloc) in ambienti raccolti senza immondizia. -se usi copia, allora devi ancora rilasciarlo in dealloc. -Usalo se hai bisogno del valore dell'oggetto così com'è in questo momento e non vuoi che quel valore rifletta le modifiche apportate da altri proprietari dell'oggetto. Dovrai rilasciare l'oggetto al termine perché stai conservando la copia.

Esempio:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;

2
Penso che dopo l'arco, trattenersi non sia più utilizzato.
Mert

1
l'elenco completo manca di 2 opzioni: setter e getter, che sono anche le uniche opzioni che richiedono argomento.
Scott Chu,

forte o trattenuto è predefinito solo per il tipo di oggetto. Non può essere utilizzato per tipi primitivi.
Saleh Enam Shohag,

9

È possibile accedere alla proprietà atomica con un solo thread alla volta. È thread-safe . L'impostazione predefinita è atomica. Si prega di notare che non esiste una parola chiave atomica

Non anatomico significa che più thread possono accedere all'elemento. Non è sicuro

Quindi si dovrebbe essere molto attenti durante l'utilizzo di atomic. Come influisce sulle prestazioni del codice


3
"Nota: l'atomicità delle proprietà non è sinonimo di sicurezza del thread di un oggetto." da developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7

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.