Jaka jest różnica między odwołaniem __weak a __block?

80

Czytam dokumentację Xcode i jest coś, co mnie zastanawia:

__block typeof(self) tmpSelf = self;
[self methodThatTakesABlock:^ {
    [tmpSelf doSomething];
}];

Z dokumentacji skopiowano:

Blok stanowi silne odniesienie do przechwytywanych zmiennych. Jeśli używasz selfw bloku, blok tworzy silne odniesienie do bloku self, więc jeśli selfma również silne odniesienie do bloku (co zwykle ma), powstaje silny cykl odniesienia. Aby uniknąć cyklu, musisz utworzyć słabe (lub __block) odniesienie do siebie poza blokiem, jak w powyższym przykładzie.

Nie rozumiem, co oznacza „słaby (lub __block)”?

Jest

__block typeof(self) tmpSelf = self;

i

__weak typeof(self) tmpSelf = self;

dokładnie to samo tutaj?

W dokumencie znalazłem inny kawałek:

Uwaga: w środowisku zbierania elementów bezużytecznych, jeśli zastosujesz zarówno modyfikatory, jak __weaki __blockdo zmiennej, blok nie zapewni, że zostanie on utrzymany.

Więc jestem całkowicie zdziwiony.

HanXu
źródło

Odpowiedzi:

109

Z dokumentów o __block

Zmienne __block znajdują się w pamięci, która jest współdzielona między zakresem leksykalnym zmiennej a wszystkimi blokami i kopiami bloków zadeklarowanymi lub utworzonymi w zakresie leksykalnym zmiennej. W ten sposób pamięć przetrwa zniszczenie ramki stosu, jeśli jakiekolwiek kopie bloków zadeklarowanych w ramce przetrwają poza końcem ramki (na przykład, umieszczając gdzieś w kolejce do późniejszego wykonania). Wiele bloków w danym zakresie leksykalnym może jednocześnie używać wspólnej zmiennej.

Z dokumentów o __weak

__weak określa odniesienie, które nie utrzymuje przy życiu przywoływanego obiektu. Słabe odniesienie jest ustawiane na zero, gdy nie ma silnych odniesień do obiektu.

Więc są to różne technicznie rzeczy. __block ma na celu powstrzymanie kopiowania zmiennej z zakresu zewnętrznego do zakresu blokowego. __weak to samowyróżniający się słaby wskaźnik.

Uwaga, powiedziałem technicznie, ponieważ w twoim przypadku zrobią (prawie) to samo. Jedyną różnicą jest to, czy używasz ARC, czy nie. Jeśli Twój projekt korzysta z ARC i jest przeznaczony tylko dla iOS 4.3 i nowszych, użyj __weak. Zapewnia, że ​​odniesienie jest ustawione na zero, jeśli odniesienie do zasięgu globalnego jest w jakiś sposób zwolnione. Jeśli Twój projekt nie korzysta z ARC lub jest przeznaczony dla starszych wersji systemu operacyjnego, użyj __block.

Jest tu subtelna różnica, upewnij się, że ją rozumiesz.

EDYCJA: Kolejnym elementem układanki jest __unsafe_unretained. Ten modyfikator jest prawie taki sam jak __weak, ale dla środowisk wykonawczych starszych niż 4.3. JEDNAK nie jest ustawiona na zero i może zostawić ci wiszące wskazówki.

Paul de Lange
źródło
1
Czy to nadal ma zastosowanie do iOS7 przy użyciu ARC? Uruchomiłem profiler i widzę, że moje kontrolery są zwalniane, nawet jeśli nie używam __block lub __weak i nie odwołuję się do siebie w bloku.
Jay Q.
1
Co powiesz na używanie ich razem? __block _weak NSString *strEg;?
CyberMew
5

W trybie ręcznego liczenia referencji, __block id x; powoduje, że nie zachowuje x. W trybie ARC __block id x; domyślnie zachowuje x (tak jak wszystkie inne wartości). Aby uzyskać zachowanie trybu ręcznego liczenia odwołań w ARC, możesz użyć __unsafe_unretained __block id x ;. Jak jednak sugeruje nazwa __unsafe_unretained, posiadanie niezachowanej zmiennej jest niebezpieczne (ponieważ może dyndać) i dlatego jest odradzane. Dwie lepsze opcje to użycie __weak (jeśli nie potrzebujesz obsługi systemu iOS 4 lub OS X 10.6) lub ustawienie wartości __block na zero, aby przerwać cykl przechowywania.

apple docs

Andrei Shender
źródło
0

Oprócz innych odpowiedzi na temat __blockvs __weak, istnieje inny sposób uniknięcia cyklu utrzymania w scenariuszu.

@weakify(self);
[self methodThatTakesABlock:^ {
    @strongify(self);
    [self doSomething];
}];

Więcej informacji o @Weakify @Strongify Macro

BananZ
źródło
0

Używając self w bloku, należy używać __weak , a nie __block, ponieważ może to zachować siebie.

Jeśli potrzebujesz silnej jaźni, możesz użyć tego:

__weak typeof(self) *weakSelf = self;
[self methodThatTakesABlock:^{
    if (weakSelf) {
        __strong typeof(self) *strongSelf = weakSelf;
        [strongSelf doSomething];
    }
}];
david72
źródło