Mam obiektywną klasę C. W nim stworzyłem metodę init i ustawiłem w niej NSNotification
//Set up NSNotification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(getData)
name:@"Answer Submitted"
object:nil];
Gdzie mam ustawić [[NSNotificationCenter defaultCenter] removeObserver:self]
w tej klasie? Wiem, że w przypadku a UIViewController
mogę dodać to do viewDidUnload
metody. Co więc należy zrobić, jeśli właśnie utworzyłem obiektywną klasę c?
-(void)dealloc
a następnie dodaćremoveObserser:self
. Jest to najbardziej zalecany sposóbremoveObservers:self
dealloc
metodę w iOS 6?Odpowiedzi:
Ogólna odpowiedź brzmiałaby: „gdy tylko nie będziesz już potrzebować powiadomień”. To oczywiście nie jest satysfakcjonująca odpowiedź.
Poleciłbym dodać wywołanie
[notificationCenter removeObserver: self]
w metodziedealloc
tych klas, których zamierzasz używać jako obserwatorów, ponieważ jest to ostatnia szansa na czyste wyrejestrowanie obserwatora. To jednak ochroni Cię tylko przed awariami, ponieważ centrum powiadomień powiadamia o martwych obiektach. Nie może chronić Twojego kodu przed otrzymywaniem powiadomień, gdy Twoje obiekty nie są jeszcze / nie są w stanie, w którym mogą poprawnie obsłużyć powiadomienie. Do tego ... Patrz wyżej.Edytuj (ponieważ odpowiedź wydaje się przyciągać więcej komentarzy, niż bym myślał) Wszystko, co próbuję tutaj powiedzieć, to: naprawdę trudno jest udzielić ogólnej porady, kiedy najlepiej usunąć obserwatora z centrum powiadomień, ponieważ to zależy:
A więc najlepsza ogólna rada, jaką mogę wymyślić: ochrona aplikacji. przeciwko przynajmniej jednej możliwej awarii,
removeObserver:
zatańczdealloc
, ponieważ to ostatni punkt (w życiu obiektu), w którym możesz to zrobić czysto. Nie oznacza to: „po prostu odłóż usunięcie do momentudealloc
wywołania, a wszystko będzie dobrze”. Zamiast tego usuń obserwatora, gdy tylko obiekt nie jest już gotowy (lub wymagany) do otrzymywania powiadomień . To jest właściwy moment. Niestety, nie znając odpowiedzi na którekolwiek z powyższych pytań, nie potrafię nawet zgadnąć, kiedy to nastąpi.Zawsze możesz bezpiecznie
removeObserver:
obiekt wiele razy (i wszystkie oprócz pierwszego wywołania z danym obserwatorem to nops). A więc: pomyśl o zrobieniu tego (ponownie)dealloc
dla pewności, ale przede wszystkim: zrób to w odpowiednim momencie (który jest określony przez twój przypadek użycia).źródło
dealloc
to tylko ostatnia linia obrony przed awarią aplikacji z powodu późniejszego dostępu do nieprzydzielonego obiektu. Ale właściwym miejscem do wyrejestrowania obserwatora jest zwykle gdzie indziej (i często znacznie wcześniej w cyklu życia obiektu). Nie próbuję tu powiedzieć „Hej, po prostu zrób todealloc
i wszystko będzie dobrze”.viewWillDisappear
" Problem z udzieleniem konkretnej porady polega na tym, że tak naprawdę zależy to od rodzaju obiektu, który zarejestrujesz jako obserwatora dla jakiego rodzaju zdarzenia. Może to być właściwe rozwiązanie, aby wyrejestrować obserwatora zviewWillDisappear
(lubviewDidUnload
) dlaUIViewController
s, ale to naprawdę zależy od przypadku użycia.Uwaga: to zostało przetestowane i działa w 100%
Szybki
PresentedViewController
Cel C
W programie
iOS 6.0 > version
lepiej jest usunąć obserwatora,viewWillDisappear
ponieważviewDidUnload
metoda jest przestarzała.Wiele razy lepiej jest,
remove observer
gdy widok został usunięty z plikunavigation stack or hierarchy
.PresentedViewController
źródło
viewWillAppear:
removeObserver:self
do dowolnegoUIViewController
wydarzenia w cyklu życia prawie na pewno zrujnuje Twój tydzień. Więcej do czytania: subiektywneremoveObserver
połączeńviewWillDisappear
zgodnie ze wskazówkami jest zdecydowanie właściwą drogą, jeśli kontroler jest prezentowany przezpushViewController
. Jeślidealloc
zamiast tego umieścisz jedealloc
, nigdy nie zostaną wezwane - przynajmniej z mojego doświadczenia ...Od iOS 9 nie trzeba już usuwać obserwatorów.
https://developer.apple.com/library/mac/releasenotes/Foundation/RN-Foundation/index.html#10_11NotificationCenter
źródło
Jeśli obserwator jest dodany do kontrolera widoku , zdecydowanie polecam dodanie go
viewWillAppear
i usunięcie goviewWillDisappear
.źródło
viewWillAppear
iviewWillDisappear
dla ViewControllers?dealloc
natychmiastowego wywołania. Powrót do kontrolera widoku może następnie spowodować wiele powiadomień, jeśli obserwator zostanie dodany w poleceniach inicjalizacji.źródło
self
after[super dealloc]
mnie denerwuje ... (nawet jeśli jest mało prawdopodobne, że odbiornik faktycznie wyłuskuje wskaźnik w jakikolwiek sposób, cóż, nigdy nie wiesz, jak zaimplementowałyNSNotificationCenter
)[super dealloc]
musi być zawsze ostatnim stwierdzeniem Twojejdealloc
metody. Niszczy twój przedmiot; po uruchomieniu nie maszself
już ważnego . / cc @Dirk[super dealloc]
nie jest już potrzebneGeneralnie umieściłem to w
dealloc
metodzie.źródło
W szybkim użyciu deinit, ponieważ dealloc jest niedostępny:
Szybka dokumentacja:
źródło
* edycja: ta rada dotyczy iOS <= 5 (nawet tam powinieneś dodawać
viewWillAppear
i usuwaćviewWillDisappear
- jednak rada ma zastosowanie, jeśli z jakiegoś powodu dodałeś obserwatoraviewDidLoad
)Jeśli dodałeś obserwatora w
viewDidLoad
, powinieneś usunąć go z obudealloc
iviewDidUnload
. W przeciwnym razie dodasz go dwukrotnie, gdyviewDidLoad
zostanie wywołany poviewDidUnload
(stanie się to po ostrzeżeniu dotyczącym pamięci). Nie jest to konieczne w iOS 6, gdzieviewDidUnload
jest przestarzałe i nie zostanie wywołane (ponieważ widoki nie są już automatycznie zwalniane).źródło
Moim zdaniem poniższy kod nie ma sensu w ARC :
W iOS 6 również nie ma sensu usuwać obserwatorów
viewDidUnload
, ponieważ jest teraz przestarzały.Podsumowując, zawsze to robię
viewDidDisappear
. Zależy to jednak również od twoich wymagań, tak jak powiedział @Dirk.źródło
Myślę, że znalazłem wiarygodną odpowiedź ! Musiałem, ponieważ powyższe odpowiedzi są niejednoznaczne i wydają się sprzeczne. Przejrzałem książki kucharskie i przewodniki programowania.
Po pierwsze, styl
addObserver:
inviewWillAppear:
iremoveObserver:
inviewWillDisappear:
nie działa dla mnie (przetestowałem go), ponieważ wysyłam powiadomienie w kontrolerze widoku podrzędnego, aby wykonać kod w kontrolerze widoku nadrzędnego. Użyłbym tego stylu tylko wtedy, gdybym publikował i nasłuchiwał powiadomienia w tym samym kontrolerze widoku.Odpowiedź, na której będę polegać najbardziej, znalazłem w iOS Programming: Big Nerd Ranch Guide 4. Ufam chłopakom z BNR, ponieważ mają centra szkoleniowe iOS i nie piszą tylko kolejnej książki kucharskiej. Dokładność prawdopodobnie leży w ich najlepszym interesie.
Przykład pierwszy BNR:
addObserver:
ininit:
,removeObserver:
indealloc:
BNR, przykład drugi:
addObserver:
inawakeFromNib:
,removeObserver:
indealloc:
… Po usunięciu obserwatora
dealloc:
nie używają[super dealloc];
Mam nadzieję, że pomoże to następnej osobie…
Aktualizuję ten post, ponieważ Apple prawie całkowicie odszedł od Storyboardów, więc powyższe może nie dotyczyć wszystkich sytuacji. Ważną rzeczą (i powodem, dla którego dodałem ten post w pierwszej kolejności) jest zwracanie uwagi, jeśli ktoś
viewWillDisappear:
dzwoni. To nie dla mnie, gdy aplikacja weszła w tło.źródło
Zaakceptowana odpowiedź nie jest bezpieczna i może spowodować wyciek pamięci. Proszę zostawić wyrejestrowanie w dealloc, ale także wyrejestrowanie w widoku Zniknie (to jest oczywiście, jeśli zarejestrujesz się w viewWillAppear) .... TO CO ZROBIŁEM I DZIAŁA WSPANIAŁE! :)
źródło
Należy również to zauważyć
viewWillDisappear
jest to wywoływane również wtedy, gdy kontroler widoku przedstawia nowy UIView. Ten delegat po prostu wskazuje, że główny widok kontrolera widoku nie jest widoczny na wyświetlaczu.W takim przypadku cofnięcie przydziału powiadomienia w
viewWillDisappear
może być niewygodne, jeśli używamy powiadomienia, aby umożliwić komunikację interfejsu użytkownika z nadrzędnym kontrolerem widoku.Jako rozwiązanie zwykle usuwam obserwatora jedną z tych dwóch metod:
Z podobnych powodów przy pierwszym zgłoszeniu muszę liczyć się z tym, że ilekroć widok z pojawi się nad kontrolerem
viewWillAppear
to odpalana jest metoda. To z kolei spowoduje wygenerowanie wielu kopii tego samego powiadomienia. Ponieważ nie ma sposobu, aby sprawdzić, czy powiadomienie jest już aktywne, rozwiązuję problem, usuwając powiadomienie przed dodaniem:źródło
SWIFT 3
Istnieją dwa przypadki użycia powiadomień: - są potrzebne tylko wtedy, gdy kontroler widoku jest na ekranie; - są potrzebne zawsze, nawet jeśli użytkownik otworzył inny ekran nad prądem.
W pierwszym przypadku poprawne miejsce do dodania i usunięcia obserwatora to:
w drugim przypadku prawidłowy sposób to:
I nigdy nie umieścić
removeObserver
wdeinit{ ... }
- to błąd!źródło
źródło