Jak naprawić " Przechwytywanie 'bloku' mocno w tym bloku prawdopodobnie doprowadzi do cyklu zatrzymania"

Pracuję nad tym kodem, który wykonuje długą asynchroniczną operację w sieci i po jej zakończeniu uruchamia blok zakończenia, w którym wykonywany jest test i jeśli zmienna otrzyma określoną wartość, kolejna długa operacja powinna rozpocząć się natychmiast:

-(void) performOperation
{

    void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request){


        int variable=0;

        // Do completion operation A
        //...
        //...

        // Do completion operation B                
        //Get the variable value

        if(variable>0){
            [self doLengthyAsynchronousOperationWithCompletionBlock: completionBlock];
        }

    };

//Perform the lenhgty operation with the above completionBlock
    [self doLengthyAsynchronousOperationWithCompletionBlock: completionBlock];

}

-(void) doLengthyAsynchronousOperationWithCompletionBlock: completionBlock
{
    //Do some lengthy asynchronous stuff
}

Z tego kodu otrzymuję Ostrzeżenie od kompilatora:

WARNING: Block pointer variable 'completionBlock' is uninitialized when caputerd by the block

Zmieniłem:

void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request)

W:

__block void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request)

Ale dostaję to drugie Ostrzeżenie:

WARNING 2: Capturing 'completionBlock' strongly in this block is likely to lead to a retain cycle

Jak mogę naprawić to?

Dzięki

Nicola

Author: nsgulliver, 2013-03-26

1 answers

WARNING: Block pointer variable 'completionBlock' is unnitialized po przechwyceniu przez blok

Dzieje się tak, ponieważ zmienne blokowe inicjowane do rekurencyjnego bloku wymagają przechowywania __block.

  • zmienne wewnątrz bloku są kopiowane, chyba że są zadeklarowane przez __block, w którym to przypadku są przekazywane jako referencja.
  • gdy rekurencyjny blok jest przypisany do zmiennej blokowej, tworzenie odbywa się przed przypisaniem i takie tworzenie uruchamia zmienną przyjąłem. Biorąc pod uwagę, że zmienna nie została jeszcze przypisana, skopiowana zmienna będzie miała złą wartość i spowoduje awarię po uruchomieniu bloku.
  • ale jeśli dodamy __block, blok zostanie utworzony z odniesieniem do zmiennej. Wtedy zmienna zostanie zainicjalizowana do utworzonego bloku i blok będzie gotowy do użycia.

WARNING: Przechwytywanie' completionBlock ' mocno w tym bloku jest prawdopodobne aby doprowadzić do cyklu zatrzymania

To dzieje się tak, ponieważ zmienna blokowa jest silnym odniesieniem do bloku, a sam blok odnosi się do zmiennej (ponieważ jak widzieliśmy wcześniej, zmienna ma __block, więc jest odwołana zamiast kopiowana).

Więc potrzebujemy

  • słabe odniesienie do silnej zmiennej wewnątrz bloku.
  • i silne odniesienie na zewnątrz, aby zapobiec dealokacji bloku podczas zakresu metody, w której został utworzony.
    void(^ completionBlock) (id obj, NSError *err, NSURLRequest *request);
    void(^ __block __weak weakCompletionBlock) (id obj, NSError *err, NSURLRequest *request);
    weakCompletionBlock = completionBlock = ^(id obj,NSError *err, NSURLRequest *request){
        [self lengthyAsyncMethod:weakCompletionBlock];
    };

Nazwa doLengthyAsynchronousOperationWithCompletionBlock sugeruje że metoda może przetrwać zakres metody, w którym tworzony jest blok. Biorąc pod uwagę, że kompilator nie kopiuje bloku przekazanego jako argument, zadaniem tej metody jest skopiowanie tego bloku. Jeśli używamy tego bloku z kodem Block aware (np: dispatch_async()), dzieje się to automatycznie.

Gdybyśmy przypisali ten blok do zmiennej instancji, potrzebowalibyśmy @property(copy) i słabego odniesienia do self wewnątrz bloku, ale tak nie jest, więc po prostu używamy self.

 29
Author: Jano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-27 15:43:34