Kontroler widoku zostanie wysłany komunikat, mimo że został on wyłączony

Nie jestem pewien, czy coś się zmieniło w iPhone SDK 3.0, ale dostaję najdziwniejszy błąd. Mam hierarchię kontrolerów widoku, w której przełączam się między kontrolerami widoku w zależności od orientacji interfejsu. Z tego, co mogę powiedzieć, błąd jest spowodowany za każdym razem, gdy obracam interfejs kontroler widoku, który został dealokowany, jest wysyłany komunikat shouldAutorotateToInterfaceOrientation. To jest backtrace dla błędu:

#0 0x01dc43a7 in ___forwarding___
#1 0x01da06c2 in __forwarding_prep_0___
#2 0x002e6733 in -[UIWindow _shouldAutorotateToInterfaceOrientation:]
#3 0x002e6562 in -[UIWindow _updateToInterfaceOrientation:duration:force:]
#4 0x002e6515 in -[UIWindow _updateInterfaceOrientationFromDeviceOrientation]
#5 0x0004d63a in _nsnote_callback
#6 0x01d8f005 in _CFXNotificationPostNotification
#7 0x0004aef0 in -[NSNotificationCenter postNotificationName:object:userInfo:]
#8 0x0045b454 in -[UIDevice setOrientation:]
#9 0x002d6890 in -[UIApplication handleEvent:withNewEvent:]
#10 0x002d16d3 in -[UIApplication sendEvent:]
#11 0x002d80b5 in _UIApplicationHandleEvent
#12 0x024c2ef1 in PurpleEventCallback
#13 0x01d9bb80 in CFRunLoopRunSpecific
#14 0x01d9ac48 in CFRunLoopRunInMode
#15 0x024c17ad in GSEventRunModal
#16 0x024c1872 in GSEventRun
#17 0x002d9003 in UIApplicationMain
#18 0x00002d50 in main at main.m:14

Błąd, który jest drukowany na konsola debugowania z NSZombieEnabled to:

2009-10-18 20:28:34.404 Restaurants[12428:207] *** -[ToolbarController respondsToSelector:]: message sent to deallocated instance 0x3b2b2a0
(gdb) continue
Current language:  auto; currently objective-c
2009-10-18 20:31:43.496 Restaurants[12428:207] *** NSInvocation: warning: object 0x3b2b2a0 of class '_NSZombie_BeltToolbarController' does not implement methodSignatureForSelector: -- trouble ahead
2009-10-18 20:31:43.496 Restaurants[12428:207] *** NSInvocation: warning: object 0x3b2b2a0 of class '_NSZombie_BeltToolbarController' does not implement doesNotRecognizeSelector: -- abort

Nie mogę zrozumieć, dlaczego system próbuje wysłać wiadomość do tego kontrolera, mimo że został on dealokowany i czy istnieje sposób, aby powiedzieć systemowi, że kontroler już nie istnieje.

[UPDATE]: Przygotowałem przykładowy projekt replikujący błąd: download

Załaduj aplikację, a następnie kilka razy zmień orientację symulatora z poziomej na pionową i powinno to nastąpić. Mam próbowałem tego samego kodu na fizycznym telefonie i zachowuje się dokładnie tak samo, więc nie jest to problem związany z symulatorem.

[UPDATE]: Wykorzystałem jedną z moich próśb o wsparcie w zespole technicznym Apple, aby sprawdzić, czy mogą mi pomóc dotrzeć do sedna tej sprawy. Opublikuje rozwiązanie-jeśli takie mają-tutaj. Dzięki za pomoc.

Author: Machavity, 2009-10-18

9 answers

Send-removeObserver: self do centrum powiadomień w metodzie-dealloc.

 4
Author: NSResponder,
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
2009-10-18 20:36:35

Więc po tygodniu oczekiwania, Pomoc techniczna programisty Apple zdołała pomóc mi rozwiązać mój problem. Oto ich odpowiedź:

"przejrzałem Twój kod i znalazłem kilka rzeczy, o które musisz się martwić o, niektóre z nich mogą przyczynić się do twój problem. W Twoim ControllerSwitchAppDelegate.m źródło, realizujesz Metoda" didRotate". Może być warto sprawdzić orientację urządzenia powiadomienia w kontrolerze widoku poziom, a nie na Uiaplikacja poziom. To sprawi, że Twój kod znacznie prostsze i hermetyzowane, co pozwala każdy kontroler widoku, który jest wyświetlany na obsługa własnej logiki obrotu. Ty korzystają również z wielu widoków kontrolerów jednocześnie, że będąc, obie właściwości "widoku" są dodawane i usuwane, gdy urządzenie jest obracany. To nie jest do końca wspólne podejście, w którym UIKit. Chodzi o to, aby zaprezentować jeden kontroler widoku (lub jego właściwość view) na raz i nie mieć widoku nadrzędnego Zamiana kontrolera w innym widoku podrzędnym Kontrolery. / Align = "left" / Twoje podejście wydaje się wykonalne, ale w na dłuższą metę, polecam inny podejdźcie.

Mamy próbkę o nazwie "AlternateViews", które można znaleźć na - http://developer.apple.com/iphone/library/samplecode/AlternateViews/index.html

W tej próbce, to prawie tak to, czego potrzebujesz. Zapewnia on "alternatywny" kontroler widoku dla biorąc pod uwagę orientację urządzenia. Na tylko prezentuje jeden kontroler widoku nad inne użycie "presentModalViewController" z właściwość przejściowa zwana "modalTransitionStyle", który da ty a cross fade affect."

Skończyło się na użyciu super kontrolera widoku, który prezentował i odrzucał Kontrolery widoku. Zamiast wymieniać Kontrolery widoku i usuwać widoki podrzędne za pomocą AppDelegate.

 4
Author: Michael Gaylord,
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
2009-10-30 10:21:15

Dużo zamieszania... zobaczmy, czy to pomoże:

Nie mogę zrozumieć, dlaczego system próbuje przekazać to kontroler mimo, że został dealokacji i czy jest sposób na stwierdzenie system, którego kontroler nie istnieć dłużej.

Podczas gdy dealokacja niszczy instancję obiektu, nie niszczy odniesień do tych instancji. Po włączeniu wykrywania Zombie deallokacja powoduje, że runtime zastępuje zombie na przykład. Następnie zombie wykrywa i rejestruje, gdy jest wysyłany.

Powodem, dla którego tak się dzieje, jest fakt, że obiekt został dealokowany bez usuwania wszystkich odniesień do obiektu z wykresu obiektów aplikacji. W tym przypadku wygląda na to, że dealokowany kontroler nigdy nie został wyłączony jako kontroler z instancji UIWindow.

To jest, przetwarzanie zgłoszenia to czerwony śledź. W tym backtrace, zgłoszenie ma już zostały dostarczone i UIWindow jest w trakcie przetwarzania go. Tak więc problem jest gdzieś pomiędzy UIWindow a Twoją aplikacją. Najprawdopodobniej twój obiekt został zdalokowany zanim został usunięty z okna jako jego kontroler lub delegat.

Zanim twój program naprawdę skończy z obiektem -- przed wysłaniem ostatniego -release wywołania, które równoważy Ostatnie istniejące -retain wywołane Lub wywołane przez Twoją aplikację -- musisz upewnić się, że wszystkie słabe odwołania do obiekt został zniszczony. Na przykład, jeśli twój obiekt jest delegatem UIWindow, upewnij się, że delegat okna został ustawiony na nil (lub jakiś inny obiekt) przed wysłaniem ostatniego -release.

Teraz, w tym przypadku, może być również po prostu, że zbytnio zwolniłeś obiekt. Możesz nadal potrzebować obiektu w pobliżu, ale dodatkowe -release lub -autorelease powoduje, że zostanie zniszczony, zanim skończysz z nim.

 2
Author: bbum,
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
2009-10-19 15:50:44

Jeśli kogoś to obchodzi, prostym rozwiązaniem jest stworzenie kontrolera widoku głównego + widoku, który nigdy się nie zmieni.

Given SomeViewController + SomeView A, and SomeViewController + SomeView B, if you add view A to the window as a subview, then add view B as a subview and remove view A, the app will crash on rotate.

Aby zapobiec awarii, Utwórz ogólny interfejs UIViewController + UIView X i dodaj widok X do okna jako podgląd podrzędny. Dodawanie i usuwanie widoków A i B do / z widoku X, a nie okno bezpośrednio. Aplikacja nie będzie się już zawieszać.

Zauważ, że nie wystarczy tylko dodać widok do okna; musisz dodać widok, który ma kontroler widoku.

 2
Author: Mark Smith,
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
2009-11-20 22:30:16

Jest to dobry powód, aby ustawić ToolbarController = nil po jego zwolnieniu. Bezpiecznie jest wysyłać wiadomości do nil, ale nie do adresów dealokowanych obiektów. W tym przypadku wysyłanie wiadomości na adres obiektu, który nie kończy się, co powoduje awarię.

To strata czasu, aby sprawdzić ToolbarController != nil przed wysłaniem wiadomości, ponieważ jeśli jest zero, to można wysłać wiadomość bezpiecznie. jeśli nie jest zerowy i ważny, zwróci tak lub nie. Ale jeśli jest to wskaźnik dealokacji pamięci (tak jak tutaj) i tak się rozbije.

 1
Author: Abizern,
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
2009-10-18 18:54:45

Też napotkałem ten problem. Kolejność zdarzeń jest następująca:

(1) tworzy pojedynczy obiekt UIWindow aplikacji

(2) Dodaj do okna subview zarządzany przez kontroler widoku

(3) Usuń pierwszy widok i dodaj Nowy

Jeśli później obrócę urządzenie, aplikacja ulegnie awarii z powodu komunikatu wysłanego do dealokowanego kontrolera widoku. (Właściwie to wysyła go do kontrolera pierwszego widoku.) Stara się wyślij- [respondsToSelector:@selector (shouldAutorotateToInterfaceOrientation:)].

Jeśli aplikacja działa tylko w trybie portretowym, możesz sprawić, że problem zniknie, dodając kategorię do UIWindow, która nadpisuje _shouldAutorotateToInterfaceOrientation: aby zwrócić NO dla wszystkiego innego niż tryb portretowy.

Oczywiście, to nie jest realne rozwiązanie. Sprawdziłem dwukrotnie-trzykrotnie mój kod i nie mogę znaleźć powodu, dla którego okno powinno wysyłać tę wiadomość do kontrolera dla widok, który został usunięty z ekranu i dealokowany. Wydaje się, że problem ten pojawił się również w 3.0, a nie wcześniej. Może robię coś głupiego, ale naprawdę wydaje się, że w pracy jest coś dziwnego.

 1
Author: Mark Smith,
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
2009-10-19 00:01:53

Też miałem ten sam problem, ale nie mogłem zostawić kontrolera w pobliżu, jak sugerował Mark Smith. Wydawało się, że usunięcie kontrolera widoku z autorelease zamiast release lub zatrzymaną właściwością wystarczy.

Wygląda na to, że nadrzędny UIWindow / framework potrzebuje kontrolera widoku, aby trochę dłużej się kręcił, aby umożliwić mu usunięcie łącza delegata.

 1
Author: gazreese,
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
2009-12-30 16:19:58

Miałem ten sam problem, dopóki nie usunąłem kilku' wpadających ' linii kodu, których używałem do wypychania animacji takich jak te:

UIView* superv = navigationController.view.superview;

[navigationController.view removeFromSuperview];

[superv addSubview:navigationController.view];

Zdecydowanie, powyższe jest "łamanie" sposób, ponieważ 3.0 SDK został wydany przez Apple. Zostałem zmuszony do użycia podejścia push/pop zamiast. Nie miałem problemu z 2.x również. Upewnij się, że nie masz czegoś podobnego w swoim kodzie.

Nadzieja, to pomaga.
 0
Author: Mike Orlov,
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
2009-10-23 17:13:23

Zamieściłem tutaj odpowiedź:

Https://stackoverflow.com/a/19237139/539149

I had a place that said:

[viewController release];
viewController = NULL;

Co spowodowało dwukrotne wywołanie release (więc pamięć została uwolniona natychmiast), ale zombie nie został ujawniony, dopóki obiekt należący do iOS nie spróbował odwołać się do obiektu później w głównym wątku.

 0
Author: Zack Morris,
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-05-23 12:09:37