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 non variabili di istanza in modo che probabilmente non cadano nella categoria dei cicli di conservazione che ho 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?

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.

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top