ARC significa che il compilatore si occupa della gestione della memoria, non-ARC significa che si prende cura di esso, ma in entrambi i casi la gestione della memoria funziona esattamente allo stesso modo:
- Se un oggetto deve rimanere in vita, la sua mantenere il contatore viene incrementato (che è quello che
retain
fa)
- Se un oggetto non è più necessaria, il suo mantenere contatore viene decrementato prima del riferimento ad esso viene perso (che è quello che
release
fa)
- Se hai finito con un oggetto, ma non deve ancora morire, ad es poiché è necessario restituirlo come risultato del metodo (e non si desidera restituire un oggetto morto), deve essere aggiunto a un pool di autorelease che diminuirà il conteggio dei ritardi in un secondo momento (è ciò che fa
autorelease
, è come "chiama release
su quell'oggetto in un momento futuro.")
- Gli oggetti appena creati hanno un conteggio di ritenzione di
1
.
- Se il conteggio di ritenzione raggiunge lo zero, l'oggetto viene liberato.
Se si fa tutto da solo o il compilatore lo fa per te, non ha alcun ruolo. Dopo la compilazione, questi metodi vengono chiamati, anche con ARC, ma con ARC il compilatore ha deciso per te quando viene chiamato il metodo. C'è un po 'di magia extra, ad es. ARC non deve sempre aggiungere oggetti ai pool di autorelease quando li restituisce come risultato del metodo, spesso può essere ottimizzato, ma non devi preoccuparti poiché questa magia viene applicata solo se il chiamante e il metodo chiamato stanno entrambi utilizzando ARCO; se uno di questi non lo è, viene utilizzato un normale autorelease
(che funziona ancora in ARC esattamente come prima).
L'unica cosa di cui ci si deve preoccupare è il mantenimento dei cicli. Sia che si utilizzi ARC o meno, il conteggio dei riferimenti non può gestire i cicli di conservazione. Nessuna differenza qui.
Insidie? Attento con il bridging gratuito. A NSString *
e a CFStringRef
sono in effetti la stessa cosa, ma ARC non conosce il mondo CF, quindi mentre ARC si occupa dello NSString
, è necessario occuparsi dello CFString
. Quando usi ARC, devi dire a ARC come fare il bridge.
CFStringRef cfstr = ...;
NSString * nsstr = (__bridge_transfer NSString *)cfstr;
// NSString * nsstr = [(NSString *)cfstr autorelease];
codice sopra significa "ARC, si prega di prendere proprietà di tale oggetto CFString
e prendersi cura di rilasciarlo non appena si è fatto con esso". Il codice si comporta come il codice mostrato nel commento qui sotto; così attento, dovrebbe avere un conteggio resti di almeno uno e ARC lo rilascerà almeno una volta, solo non ancora. Il contrario:
NSString * nsstr = ...;
CFStringRef cfstr = (__bridge_retained CFStringRef)cftr;
// CFStringRef cfstr = (CFStringRef)[nsstr retain];
codice sopra significa "ARC, per favore mi dia proprietà di tale NSString
, mi prenderò cura di rilasciarlo una volta ho finito con esso". Certo, devi mantenere questa promessa! A un certo punto dovrai chiamare lo CFRelease(cfstr)
altrimenti perderai memoria.
Infine c'è (__bridge ...)
che è solo un cast di tipo, non viene trasferita alcuna proprietà. Questo tipo di cast è pericoloso in quanto può creare puntatori penzolanti se si tenta di mantenere il risultato del cast intorno. Solitamente lo si usa quando si alimenta un oggetto ARC a una funzione che si aspetta un oggetto CF, poiché ARC sicuramente manterrà vivo l'oggetto finché la funzione non ritorna, ad es.questo è sempre sicuro:
doSomethingWithString((__bridge CFStringRef)nsstr);
Anche se ARC è stato permesso di rilasciare nsstr
in qualsiasi momento, senza il codice di sotto della linea mai accessi più, sarà certamente non rilasciarlo prima che questa funzione è tornato e argomenti della funzione sono da definizione garantita solo per rimanere in vita fino a quando la funzione non ritorna (nel caso in cui la funzione desideri mantenere la stringa attiva, deve mantenerla e quindi ARC non la deallocerà dopo averla rilasciata poiché il conteggio dei ritiri non diventerà zero).
La cosa maggior parte delle persone sembrano lottare con sta passando ARC oggetti come void *
contesto, come a volte si deve con API più vecchio, ma che è in realtà morto semplice:
- (void)doIt {
NSDictionary myCallbackContext = ...;
[obj doSomethingWithCallbackSelector:@selector(iAmDone:)
context:(__bridge_retained void *)myCallbackContext
];
// Bridge cast above makes sure that ARC won't kill
// myCallbackContext prior to returning from this method.
// Think of:
// [obj doSomethingWithCallbackSelector:@selector(iAmDone:)
// context:(void *)[myCallbackContext retain]
// ];
}
// ...
- (void)iAmDone:(void *)context {
NSDictionary * contextDict = (__bridge_transfer NSDictionary *)context;
// Use contextDict as you you like, ARC will release it
// prior to returning from this method. Think of:
// NSDictionary * contextDict = [(NSDictionary *)context autorelease];
}
E devo vero e proprio grande per te che non è così scontato a prima vista. Si prega di prendere in considerazione questo codice:
@implementation SomeObject {
id _someIVAR;
}
- (void)someMethod {
id someValue = ...;
_someIVAR = someValue;
}
Questo codice non è la stessa in ARC e non ARC. In ARC tutte le variabili sono forti di default, quindi in ARC questo codice si comporta proprio come questo codice avrebbe:
@interface SomeObject
@property (retain,nonatomic) id someIVAR;
@end
@implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
Assegnazione someValue
manterrà esso, l'oggetto rimane vivo! Nel settore non-ARC il codice si comporterà come questo:
@interface SomeObject
@property (assign,nonatomic) id someIVAR;
@end
@implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
Nota la proprietà è diverso, come Ivar a non-ARC non sono né strong
o weak
, non sono nulla, sono solo puntatori (in ARC che è chiamato __unsafe_unretained
e la parola chiave qui è non sicuro).
Quindi, se si dispone di codice che utilizza direttamente ivars e non utilizza le proprietà con setter/getter per accedervi, passare da non ARC a ARC può causare cicli di conservazione nel codice utilizzato per la gestione della memoria. D'altra parte, passando da ARC a non-ARC, un codice come questo può causare puntatori penzolanti (puntatori agli oggetti precedenti ma poiché l'oggetto è già morto, questi puntano verso il nulla e il loro utilizzo ha risultati imprevedibili), come oggetti che prima essere tenuto in vita prima che possa morire inaspettatamente.
questo sembra essere il consenso. Grazie per l'aiuto. – TomSwift