6

Widziałem następuje używane:Dlaczego nie powinienem używać słabego wskaźnika do siebie w bloku przekazanym do dispatch_after()?

double delayInSeconds = 2.0; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    //code to be executed on the main queue after delay 
    [self doSometingWithObject:obj1 andAnotherObject:obj2]; 
}); 

Ale nie powinno używać słaby siebie w bloku?

__weak typeof(self) weakSelf = self; 
double delayInSeconds = 2.0; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    //code to be executed on the main queue after delay 
    [weakSelf doSometingWithObject:obj1 andAnotherObject:obj2]; 
}); 

Jestem nowicjuszem dla GCD i bloków i staram się wypracować jak najbardziej poprawne użycie. Wielkie dzięki za wskazówki na ten temat.

+2

To zależy. Czy potrzebujesz wywołania 'doSometingWithObject' [sic] nawet po wyłączeniu kontrolera widoku, czy nie? Czasem robisz (np. Być może coś zapisujesz, aktualizujesz obiekt modelu, publikujesz ważne żądanie sieciowe, cokolwiek), w takim przypadku użyjesz poprzedniej składni. Ale czasami tego nie robisz (np. Chcesz zaktualizować jakiś obiekt interfejsu użytkownika w widoku, który mógł już zostać odrzucony), w takim przypadku użyjesz tego ostatniego. – Rob

+1

To zależy od tego, co chcesz zrobić, jeśli 'self' ma szansę zostać zwolniony, zanim opóźnienie się skończy. Pierwszy fragment uniemożliwiłby to, więc wywołanie w bloku zawsze miało miejsce, gdy drugie pozwoliłoby na zwolnienie siebie, a blok nie zrobiłby nic. Zwykle słabe ja stosuje się do zapobiegania cyklom zatrzymania, ale nie ma cyklu zatrzymania w tym bloku w żaden sposób – dan

Odpowiedz

6

To zależy od pożądanego zachowania.

  • Pierwsza składnia (odnosząc się do self w bloku) będzie utrzymywać silne odniesienie do kontrolera widoku aż dispatch_after pożarów i doSometingWithObject pomyślnie uruchomić. Stanie się tak, nawet jeśli widok związany z tym kontrolerem widoku zostanie odrzucony w okresie interwencji.

    Używałbyś tego wzorca tylko w przypadkach, gdy absolutnie potrzebujesz tej metody, nawet jeśli widok związany z tym kontrolerem widoku został odrzucony. Na przykład, jeśli ta metoda aktualizuje niektóre obiekty modelu, zapisuje coś w pamięci trwałej, publikuje żądanie sieciowe itp.

  • Druga składnia (wzór weakSelf) nie będzie zawierała silnego odniesienia do kontrolera widoku, iw związku z tym, jeśli widok związany z kontrolerem widoku został odrzucony do czasu uruchomienia bloku, kontroler widoku zostanie zwolniony, a weakSelf będzie nil, a zatem doSometingWithObject nie zostanie wywołany. (Oczywiście, jeśli widok nie został jeszcze odrzucony, kontroler widoku nie zostanie zwolniony, weakSelf nie będzie nil i ta metoda zostanie wywołana.)

    Zrobisz to, jeśli dana metoda musi tylko zadzwonić, jeśli widok nie został jeszcze odrzucony. Na przykład, jeśli jedynym celem tej metody jest aktualizacja niektórych obiektów interfejsu użytkownika w tym widoku, oczywiście nie trzeba wywoływać tej metody, jeśli widok został już odrzucony. I w tym scenariuszu, ogólnie wolisz używać weakSelf, aby kontroler widoku był natychmiast zwolniony, gdy nie jest już potrzebny.

  • Tylko dla kompletności wywodu, jest faktycznie jedna trzecia permutacji tego wzorca, czasami (żartobliwie) zwany „taniec” weakSelf/strongSelf:

    __weak typeof(self) weakSelf = self; 
    double delayInSeconds = 2.0; 
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
        //code to be executed on the main queue after delay 
        typeof(self) strongSelf = weakSelf; 
        if (strongSelf) { 
         [strongSelf doSomethingWithObject:obj1 andAnotherObject:obj2]; 
         [strongSelf doSomethingElseWithObject:obj1]; 
        } 
    }); 
    

    Ten wzór jest bardzo podobny do drugiego przykład, gdzie metody nie są wywoływane, jeśli następuje deallocacja self. Używasz tego wzorca, gdy chcesz słabego odniesienia, ale albo (a) musisz upewnić się, że nie jest zwolniony podczas działania bloku; lub (b) kiedy musisz sprawdzić, czy jest to nil, czy nie, ale chcesz uniknąć warunków wyścigu.

-2

większą część za pomocą bloku jest tak:

__weak typeof(self) weakSelf = self; 
double delayInSeconds = 2.0; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    //code to be executed on the main queue after delay 
    __strong __typeof(weakSelf)strongSelf = weakSelf; 
    [strongSelf doSometingWithObject:obj1 andAnotherObject:obj2]; 
}); 

Tworzenie __strong odniesienie w bloku nie zwiększy liczbę odwołań pamięci. Zostanie zwolniony, gdy blok zostanie ukończony.

https://dhoerl.wordpress.com/2013/04/23/i-finally-figured-out-weakself-and-strongself/

+0

Odwołanie '__strong' w bloku * nie * zwiększa liczbę odwołań - ale tylko podczas działania bloku. Po zakończeniu bloku ponownie zmniejszy liczbę. – Nef10

2

Słaby wskaźnik samo stosuje się do zapobiegania zatrzymywania cykli. W pierwszym fragmencie kodu nie ma ryzyka zatrzymania cyklu.

Cykl zatrzymania byłby problemem, gdyby obiekt zatrzymał blok, który zachowuje obiekt, jeśli obiekt miał zwolnić blok tylko wtedy, gdy sam został zwolniony. Żaden z tych warunków nie ma w tym przypadku zastosowania.

dispatch_after() uruchomi dostarczony blok po wyznaczonym czasie, a następnie zwolni blok. To zwolnienie bloku nie jest zależne od zwolnienia twojego obiektu. Nie ma cyklu zatrzymania.

Powiązane problemy