Jaka jest różnica między słabym a blokowym odniesieniem?

Czytam dokumentację Xcode, a oto coś, co mnie zastanawia:

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

Z dokumentacji skopiowano:

Blok tworzy silne odniesienie do zmiennych, które przechwytuje. W przypadku stosowania self w bloku blok tworzy silne odniesienie do self, więc jeśli self ma również silne odniesienie do bloku (który zazwyczaj robi), silne wyniki cyklu odniesienia. Aby uniknąć cyklu, potrzebujesz aby utworzyć słaby (lub __block) odniesienie do siebie poza blokiem, jako w powyższym przykładzie.

Nie rozumiem co znaczy " słaby (lub __block)"?

Jest

__block typeof(self) tmpSelf = self;

I

__weak typeof(self) tmpSelf = self;

Dokładnie to samo tutaj?

Znalazłem inny kawałek w dokumencie:

Uwaga: w środowisku śmieci, jeśli zastosujesz zarówno __weak, jak i __block modyfikatory do zmiennej, wtedy blok nie zapewni, że zostanie utrzymany przy życiu.

Więc jestem całkowicie zdziwiony.

Author: Josh Caswell, 2012-08-02

3 answers

From the docs about _ _ block

_ _ zmienne blokowe żyją w magazynie, który jest współdzielony między zakresem leksykalnym zmiennej a wszystkimi blokami i kopiami bloków zadeklarowanymi lub utworzonymi w zakresie leksykalnym zmiennej. Tak więc, magazyn przetrwa zniszczenie ramki stosu, jeśli jakiekolwiek kopie bloków zadeklarowanych w ramce przetrwają poza końcem ramki (na przykład przez zapytanie gdzieś do późniejszego wykonania). Wiele bloków w danym zakresie leksykalnym może jednocześnie używaj współdzielonej zmiennej.

From the docs about _ _ weak

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

Więc są to technicznie różne rzeczy. __block polega na zatrzymaniu kopiowania zmiennej z zewnętrznego zakresu do zakresu bloku. __weak jest samooddzielającym się słabym wskaźnikiem.

Uwaga powiedziałem technicznie, bo w Twoim przypadku zrobią (prawie) to samo. Jedyną różnicą jest to, czy używasz ARC, czy nie. Jeśli twój projekt używa ARC i jest tylko dla iOS4. 3 i nowszych, użyj _ _ weak. Zapewnia, że odniesienie jest ustawione na nil, jeśli globalne odniesienie do zakresu zostanie uwolnione. Jeśli twój projekt nie używa ARC lub jest przeznaczony dla starszych wersji systemu operacyjnego, użyj _ _ block.

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

EDIT: kolejny element układanki to _ _ unsafe_unrethed. To modyfikator jest prawie taki sam jak _ _ słaby, ale dla środowiska uruchomieniowego sprzed 4.3. Jednak nie jest ustawiony na zero i może pozostawić cię z wiszącymi wskaźnikami.

 103
Author: Paul de Lange,
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
2012-08-02 08:25:26

W trybie ręcznego zliczania referencji, _ _ block id x; powoduje, że nie zachowuje x. w trybie łuku, __block id x; domyślnie zachowuje X (tak jak wszystkie inne wartości). Aby uzyskać zachowanie trybu ręcznego zliczania referencji pod Arc, możesz użyć _ _ unsafe_unrethed _ _ block id x;. Jak sugeruje nazwa _ _ unsafe_unrethed, jednak posiadanie zmiennej nie zatrzymanej jest niebezpieczne (ponieważ może zwisać) i dlatego jest zniechęcane. Dwie lepsze opcje to albo użycie _ _ słabe (jeśli nie musisz obsługiwać iOS 4 lub OS X v10.6) lub ustawić wartość _ _ block na nil, aby przerwać cykl zachowywania.

Apple docs

 5
Author: Andrei Shender,
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
2017-01-19 18:04:01

Oprócz innych odpowiedzi na _ _ blok vs _ _ słaby, istnieje inny sposób, aby uniknąć cyklu utrzymania w swoim scenariuszu.

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

Więcej informacji o @ Weakify @ Strongify Marco

 0
Author: Jun Jie Gan,
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
2018-01-26 08:58:22