2013-04-17 4 views
10

ogni volta che devo usare una var globale o una proprietà all'interno di un blocco come questo:Evitando il "sé catturare con forza in questo blocco rischia di portare ad un ciclo di mantenere" un messaggio

self.save = ^(){ 
    if (isItSaving == NO) { 
     [self saveMyFile]; 
    } 
}; 

devo riscrivere questo come

BOOL *iis = isItSaving; 
id myself = self; 

self.save = ^(){ 
    if (iis == NO) { 
     [myself saveMyFile]; 
    } 
}; 

o Xcode si lamenta "la cattura di sé con forza in questo blocco rischia di portare ad un ciclo di mantenere ...

Si lamenta anche sulle variabili BOOL?

Ridire tutto prima di un blocco sembra essere una soluzione zoppa.

È questo il modo corretto? C'è un modo elegante?

Questa roba è brutta. Sto usando ARC.

risposta

20

Il problema si verifica solo quando si fa riferimento a self all'interno del blocco, in modo esplicito o implicito. Non viene emesso alcun avviso quando si accede a variabili globali.

Nel tuo caso hai probabilmente accesso a un (booleano) di ivar. L'accesso a ivar utilizza implicitamente self, ecco perché il compilatore ti avvisa (correttamente) di un ciclo di conservazione.

Il modo più comune per risolvere il ciclo di mantenere è:

typeof(self) __weak weakSelf = self; 

self.save = ^() { 
    typeof(weakSelf) __strong strongSelf = weakSelf; 
    if (strongSelf != nil && ! strongSelf->isItSaving) { 
     [strongSelf saveMyFile]; 
    } 
}; 

... e, sì, questo è un po 'di una parte brutta di blocchi.

+1

uomo, questo è brutto da morire. Dovendo ridichiarare tutto ... grazie. – SpaceDog

+0

@MarkAmery Sì, clang cattura sempre più problemi. Ed è corretto, la durata dell'oggetto che racchiude deve essere estesa almeno fino al termine del blocco. Modifica ... –

+1

@NikolaiRuhe * "la durata dell'oggetto che racchiude deve essere estesa almeno fino a che il blocco non termina" * - bello, non ho notato a priori alcun motivo per cui creare un forte riferimento a 'self' all'interno del blocco sarebbe preferibile usare '__unsafe_unretained', ma questa frase lo rende incredibilmente chiaro. Potrebbe anche valere la pena confrontare i due approcci nella tua risposta, se lo desideri. –

4

Usa __unsafe_unretained typeof(self) weakSelf = self;

+0

Penso che non puoi usare __unsafe_unretained con ARC – SpaceDog

0

Oltre a @ risposta di NikolaiRuhe, nel tuo esempio per dichiarare le proprietà

BOOL *iis = isItSaving; 
id myself = self; 

implica strong riferimenti, in modo da utilizzare __weak sé per evitare che il ciclo di trattenere. Quindi potresti chiederti perché è necessario dichiarare un riferimento __strong a self debole all'interno del blocco, e questo per assicurarsi che non venga rilasciato durante la vita del blocco, altrimenti weakSelf->isItSaving si interromperà se è stato rilasciato self.