19

Ho richiesto con blocco. Ma il compilatore genera un avvisoÈ probabile che la cattura di "sé" in questo blocco porti a un ciclo di conservazione

" 'sé' Cattura fortemente in questo blocco rischia di portare ad una trattenere ciclo"

__weak typeof(self) weakSelf = self; 
[generalInstaImage setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:data[@"images"][@"low_resolution"][@"url"]]] placeholderImage:[UIImage imageNamed:@"Default"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { 
    NSLog(@"success"); 
    [generalInstaImage setImage: image]; 
    [weakSelf saveImage:generalInstaImage.image withName:data[@"id"]]; 

    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { 
     NSLog(@"fail"); 
}]; 

provo esempio scrivere come weakSelf.generalInstaImage, ma poi il il compilatore genera un errore e non si compila.

+0

qual è l'errore? prova ad usare 'id' o il nome effettivo della classe invece di' typeof (self) ' – Fonix

risposta

60

considerare questo avvertimento:

Catturare self fortemente in questo blocco rischia di portare ad una trattenere ciclo

Quando si riceve l'avviso di cui sopra, si dovrebbe rivedere il tuo blocco per:

  • eventuali riferimenti espliciti a self; oppure
  • qualsiasi riferimento implicito a self causato dal riferimento a qualsiasi variabile di istanza.

Immaginiamo che abbiamo un po 'semplice proprietà di classe che era un blocco (questa sperimenterà lo stesso "mantenere ciclo" avvisi come tua domanda, ma non mancherà di tenere i miei esempi un po' più semplice):

@property (nonatomic, copy) void (^block)(void); 

E supponiamo che abbiamo avuto qualche altra proprietà di classe abbiamo deciso di utilizzare all'interno del nostro blocco:

@property (nonatomic, strong) NSString *someString; 

Se si fa riferimento self all'interno del blocco (nel mio esempio qui di seguito, nel processo di accesso questa proprietà), è ovviamente ricevere tale avviso circa il rischio trattenere ciclo:

self.block = ^{ 
    NSLog(@"%@", self.someString); 
}; 

Quella essere risolti tramite il modello che ha suggerito, e cioè:

__weak typeof(self) weakSelf = self; 

self.block = ^{ 
    NSLog(@"%@", weakSelf.someString); 
}; 

Meno ovvio, riceverete anche la "trattenere ciclo di" avviso se si fa riferimento una variabile della classe esempio all'interno del blocco, ad esempio:

self.block = ^{ 
    NSLog(@"%@", _someString); 
}; 

Questo perché la variabile di istanza _someString porta un riferimento implicito a self, ed è in realtà equivale a:

self.block = ^{ 
    NSLog(@"%@", self->_someString); 
}; 

Si potrebbe essere propenso a cercare di adottare modello sé debole anche qui, ma non si può.Se si tenta il modello weakSelf->_someString della sintassi, il compilatore vi avvertirà di questo:

Dereferenziare un puntatore __weak non è consentito a causa di possibili valore nullo causato dalla condizione di competizione, assegnarlo alla strong variabile prima

È quindi risolvere ciò utilizzando il modello weakSelf, ma anche creare una variabile locale strong all'interno del blocco e l'uso che di dereference la variabile di istanza:

__weak typeof(self) weakSelf = self; 

self.block = ^{ 
    __strong typeof(self) strongSelf = weakSelf; 

    if (strongSelf) { 
     NSLog(@"%@", strongSelf->_someString); 

     // or better, just use the property 
     // 
     // NSLog(@"%@", strongSelf.someString); 
    } 
}; 

Come parte, questa creazione di un riferimento locale strong, strongSelf, all'interno del blocco presenta anche altri vantaggi, vale a dire che se il blocco di completamento è in esecuzione in modo asincrono su un thread diverso, non è necessario preoccuparsi di self deallocato mentre il blocco è in esecuzione, con conseguenze non intenzionali.

Questo modello weakSelf/strongSelf è molto utile quando si tratta di proprietà di blocco e si desidera impedire mantenere cicli (alias cicli riferimento forti), ma al tempo stesso che self non può essere deallocato nel mezzo dell'esecuzione del blocco di completamento.

FYI, Apple discute questo modello nella discussione "cicli non banali" più avanti nella sezione Use Lifetime Qualifiers to Avoid Strong Reference Cycles della Transizione alle note di rilascio ARC.


di segnalare che hai ricevuto qualche "errore" quando si fa riferimento weakSelf.generalInstaImage nel tuo esempio. Questo è il modo corretto per risolvere questo avviso di "conservazione del ciclo", quindi se hai ricevuto un avvertimento, dovresti condividerlo con noi, oltre a mostrarci come hai dichiarato la proprietà.

+3

Risposta molto completa! +1 –

+1

Grazie :) Ho capito – Alexander

+0

"genererà un'eccezione" No, non genererà un'eccezione. Condurrà a comportamento indefinito (probabilmente un errore di segmentazione). – newacct

2

Usa __unsafe_unretained typeof(self) weakSelf = self

+3

Questo potrebbe eliminare l'avviso del compilatore, ma può avere risultati disastrosi se "self" è stato deallocato dal momento in cui viene chiamato il blocco, poiché si avrà un puntatore pendente su un oggetto deallocato. Questo è, a rischio di affermare l'ovvio, molto _unsafe._ – Rob