Z Transitioning to ARC Release NotesDlaczego musimy ustawić zmienną __block na zero?
zażycia kwalifikacyjnych, których należy unikać Silne cykli odniesienia
Można użyć kwalifikatorów całe życie unikać silnych cykli odniesienia. Na przykład , zazwyczaj jeśli masz wykres obiektów ułożonych w hierarchii nadrzędnego podrzędnego dziecka, a rodzice muszą odnosić się do swoich dzieci i na odwrót, wtedy relacja między rodzicem a dzieckiem jest silna, a rodzic - dziecko - silnym i -parent relacja słaba. Inne sytuacje mogą być bardziej subtelne, szczególnie gdy dotyczą obiektów blokowych.
W ręcznym trybie liczenia odniesień,
__block id x;
ma efekt polegający na tym, że nie zachowuje wartości . W trybie ARC domyślnie__block id x;
zachowuje wartośćx
(tylko , podobnie jak wszystkie inne wartości). Aby uzyskać ręczny tryb liczenia odniesień zachowanie w ramach ARC, można użyć__unsafe_unretained __block id x;
. Jak wskazuje nazwa__unsafe_unretained
, posiadanie niepobranej zmiennej jest niebezpieczne (ponieważ może zwisać) i dlatego jest zniechęcane. Dwiema lepszymi opcjami są: użycie__weak
(jeśli nie potrzebujesz obsługi iOS 4 lub OS X v10.6), lub ustaw wartość__block
nanil
, aby przerwać cykl zachowywania.
Okay, więc co różni się od zmiennej __block
?
Dlaczego ustawić na nil
tutaj? Czy zmienna __block
zachowała się dwukrotnie? Kto ma wszystkie odniesienia? Blok? Kupa? Stos? Groźba? Co?
Poniższy fragment kodu ilustruje ten problem za pomocą wzoru, który jest czasem używany w ręcznym liczeniu odwołań.
MyViewController *myController = [[MyViewController alloc] init…];
// ...
myController.completionHandler = ^(NSInteger result) {
[myController dismissViewControllerAnimated:YES completion:nil];
};
[self presentViewController:myController animated:YES completion:^{
[myController release];
}];
Jak opisano, zamiast tego można użyć __block
kwalifikator i ustawić zmienną MyController do nil
w obsługi realizacji:
MyViewController * __block myController = [[MyViewController alloc] init…]; //Why use __block. my controller is not changed at all
// ...
myController.completionHandler = ^(NSInteger result) {
[myController dismissViewControllerAnimated:YES completion:nil];
myController = nil; //Why set to nil here? Is __block variable retained twice? Who hold all the reference? The block? The heap? The stack? The thread? The what?
};
także dlaczego myController
nie jest ustawiony na nil
przez kompilator. Dlaczego musimy to robić? Wygląda na to, że kompilator wie, kiedy myController nie będzie już używany, a mianowicie, gdy blok wygaśnie.
"Ale sam blok również zachowa obiekt, ponieważ jest silnie odwołany z wewnątrz bloku." Czemu? Zamknięcie. –
W jaki sposób dodanie __block powoduje jakąkolwiek różnicę? –
Gdy blok przechwytuje wskaźnik do obiektu c, obiekt ten będzie zachowany, chyba że użyjesz '__weak' lub' __unsafe_unretained' (lub '__block' w kodzie innym niż ARC). –