Pamiętaj również, że cykle zachowania mogą wystąpić, jeśli twój blok odnosi się do innego obiektu, który następnie zachowujeself
.
Nie jestem pewien, czy Garbage Collection może pomóc w tych cyklach przechowywania. Jeśli obiekt zachowujący blok (który nazwiemy obiektem serwera) przeżyje self
(obiekt klienta), odniesienie doself
wnętrza bloku nie zostanie uznane za cykliczne, dopóki sam obiekt zatrzymujący nie zostanie zwolniony. Jeśli obiekt serwera znacznie przeżyje swoich klientów, możesz mieć znaczny wyciek pamięci.
Ponieważ nie ma czystych rozwiązań, polecam następujące obejścia. Możesz wybrać jedną lub więcej z nich, aby rozwiązać problem.
- Używaj bloków tylko do ukończenia , a nie do otwartych wydarzeń. Na przykład użyj bloków dla metod takich jak
doSomethingAndWhenDoneExecuteThisBlock:
, a nie metod takich jaksetNotificationHandlerBlock:
. Bloki użyte do ukończenia mają określony koniec życia i powinny zostać zwolnione przez obiekty serwera po ich ocenie. Zapobiega to zbyt długiemu cyklowi utrzymania, nawet jeśli wystąpi.
- Zrób ten słaby taniec, który opisałeś.
- Podaj metodę czyszczenia obiektu przed jego zwolnieniem, co „odłącza” obiekt od obiektów serwera, które mogą zawierać odniesienia do niego; i wywołaj tę metodę przed wywołaniem release na obiekcie. Chociaż ta metoda jest całkowicie w porządku, jeśli twój obiekt ma tylko jednego klienta (lub jest singletonem w pewnym kontekście), ale zepsuje się, jeśli ma wielu klientów. Zasadniczo pokonujesz tutaj mechanizm liczenia retencji; jest to podobne do dzwonienia
dealloc
zamiast release
.
Jeśli piszesz obiekt serwera, argumenty blokowe przyjmuj tylko do uzupełnienia. Nie akceptuj argumentów blokowych dla wywołań zwrotnych, takich jak setEventHandlerBlock:
. Zamiast tego powróć do klasycznego wzorca delegata: utwórz formalny protokół i rozgłaszaj setEventDelegate:
metodę. Nie zatrzymuj pełnomocnika. Jeśli nawet nie chcesz tworzyć formalnego protokołu, zaakceptuj selektor jako wywołanie zwrotne delegata.
I wreszcie, ten wzorzec powinien wywoływać alarmy:
- (void) dealloc {
[myServerObject releaseCallbackBlocksForObject: self];
...
}
Jeśli próbujesz odhaczyć bloki, które mogą odnosić się do self
środka dealloc
, już masz kłopoty. dealloc
może nigdy nie zostać wywołane z powodu cyklu przechowywania spowodowanego przez odwołania w bloku, co oznacza, że obiekt po prostu wycieknie, dopóki obiekt serwera nie zostanie zwolniony.
self
proxythis
tylko po to, żeby coś odwrócić. W JavaScript nazywam mojethis
domknięciaself
, więc jest to przyjemne i zrównoważone. :)