Obiettivo C Gestione della memoria con blocchi, arco e non-arco
Domanda
Ho usato i blocchi per qualche tempo ora, ma sento che ci sono cose che mi manca sulla gestione della memoria in ambienti arc e non arc. Sento che la comprensione più profonda mi farà invalidare molte perdite di memoria.
AFNetworking è il mio uso principale di blocchi in una particolare applicazione. La maggior parte delle volte, all'interno di un gestore di completamento di un'operazione, faccio qualcosa come "[Self.Myarray Addobject]".
In entrambi gli ambienti ARC e ARC abilitati, "Sé" verrà mantenuto secondo Questo articolo da Apple .
Ciò significa che ogni volta che un blocco di completamento di un'operazione di rete di AFNetworking è chiamata, il sé viene mantenuto all'interno di quel blocco e rilasciato quando quel blocco si spegne. Credo che questo si applica sia all'arco che all'arco e all'arco. Ho eseguito sia lo strumento perdite che l'analizzatore statico in modo che possa trovare perdite di memoria. Nessuno ha mostrato alcuna.
Tuttavia, non è stato fino a poco tempo è inciampato su un avvertimento che non potevo capire. Sto usando ARC in questo particolare esempio.
Ho due variabili di istanza che indicano il completamento e il fallimento di un'operazione di rete
@property (nonatomic, readwrite, copy) SFCompletionBlock completionBlock;
@property (nonatomic, readwrite, copy) SFFailureBlock failureBlock;
@synthesize failureBlock = _failureBlock;
@synthesize operation = _operation;
.
Da qualche parte nel codice, lo faccio:
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id
responseObject) {
NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
_failureBlock(error);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"nothing");
}];
.
XCode si lamenta sulla linea che chiama il fallimento, con il messaggio "Catturare" auto "fortemente in questo blocco risulta in un ciclo di conservazione. Credo che Xcode abbia ragione: il blocco del fallimento conserva il suo sé e lo sente propria copia del blocco, quindi nessuno dei due sarà deallocato.
Tuttavia, ho le seguenti domande / osservazioni.
1) Se cambio _failureblock (errore) su "self.failleureblock (Errore)" (senza virgolette) Il compilatore si arresta lamentarti. Perché? È una perdita di memoria che il compilatore manca?
2) In generale, quali sono le migliori pratiche da lavorare con i blocchi in ambienti ARC e non ARC abilitati durante l'utilizzo di blocchi che sono variabili di istanza ? Sembra che nel caso di completamento e blocchi di fallimento in Afnetworking, quei due blocchi sono
Mi piacerebbe sentire i pensieri degli altri sull'arco e il non-arco con blocchi e problemi / soluzioni con la gestione della memoria. Trovo queste situazioni in modo incline e sento che una discussione su questo è necessaria per liberare le cose.
Non so se conta, ma uso Xcode 4.4 con l'ultima LLVM.
Soluzione
.1) Se cambio _failureblock (errore) su "self.failleureblock (errore)" (senza virgolette) Il compilatore si arresta lamentarsi. Perché? È questo Una perdita di memoria Il compilatore manca?
Il ciclo di conservazione esiste in entrambi i casi. Se stai prendendo di mira iOS 5+, puoi passare in un debole riferimento a sé:
__weak MyClass *weakSelf;
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
if (weakSelf.failureBlock) weakSelf.failureBlock(error);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"nothing");
}];
.
Ora il sé non verrà mantenuto, e se è deallocato prima che venga invocato il callback, il callback è un no-op. Tuttavia, è possibile che potrebbe essere sottoposto a deallocazione mentre il callback è invocato su un filo di sfondo, quindi questo modello può creare incidenti occasionali.
.2) In generale, qual è la migliore pratica da lavorare con i blocchi in entrambi Ambienti ARC e non ARC abilitati quando si utilizzano blocchi che sono variabili di istanza? Sembra che in caso di completamento e fallimento Blocchi in Afnetworking, quei due blocchi non sono variabili di istanza così Probabilmente non cadono nella categoria dei cicli di conservazione che io descritto sopra. Ma quando si utilizzano i blocchi di avanzamento in Afnetworking, Cosa può essere fatto per evitare di conservare i cicli come quello sopra?
La maggior parte delle volte, penso è meglio non farlo Memorizza i blocchi di istanza delle variabili . Se invece restituisci il blocco da un metodo nella tua classe, avrai ancora un ciclo di conservazione, ma esiste solo dal momento in cui il metodo è invocato al tempo in cui viene rilasciato il blocco. Quindi impedirà che l'istanza sia deallocato durante l'esecuzione del blocco, ma il ciclo di conservazione termina quando viene rilasciato il blocco:
-(SFCompletionBlock)completionBlock {
return ^(AFHTTPRequestOperation *operation , id responseObject ) {
[self doSomethingWithOperation:operation];
};
}
[self.operation setCompletionBlockWithSuccess:[self completionBlock]
failure:[self failureBlock]
];
. Altri suggerimenti
.significa che ogni volta che un blocco di completamento di una rete di afnet L'operazione è chiamata, il sé viene mantenuto all'interno di quel blocco e rilasciato Quando quel blocco esce dall'ambito.
No, self
viene mantenuto dal blocco quando viene creato il blocco. E viene rilasciato quando il blocco è deallocato.
.Credo che Xcode abbia ragione: il blocco di errore mantiene sé e sé contiene la propria copia del blocco, quindi nessuno dei due sarà deallocato.
Il blocco in questione che mantiene self
è il blocco di completamento passato su setCompletionBlockWithSuccess
. self
non tiene un riferimento a questo blocco. Piuttosto, self.operation
(presumibilmente una specie di generazione di NSOperation
) conserva i blocchi mentre è in esecuzione. Quindi c'è temporaneamente un ciclo. Tuttavia, quando l'operazione è eseguita eseguendo, il ciclo sarà rotto.
.1) Se cambio _failureblock (errore) su "self.failleureblock (errore)" (senza virgolette) Il compilatore si arresta lamentarsi. Perché? È questo Una perdita di memoria Il compilatore manca?
Non ci dovrebbe essere differenza. self
viene catturato in entrambi i casi. Il compilatore non è garantito per catturare tutti i casi di cicli di conservazione.