Message sent to deallocated instance

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Message sent to deallocated instance

    Hallo,

    ich habe ein etwas merkwürdiges Phänomen:

    Ich empfange eine Remote Push Notification und möchte bei aktiver Anwendung den Nutzer fragen ob er sich die Details zu der Notification in einem modalen ViewController anschauen möchte. Dazu erzeuge ich ein UIAlertView und erstelle in der clickedButtonAtIndex() meinen ViewController und zeige diesen mithilfe presentViewController() an:

    Quellcode

    1. ​@interface AppDelegate ()
    2. @property (retain) NSDictionary *currentLaunchOptions;
    3. @end
    4. - (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    5. UIApplicationState state = [application applicationState];
    6. // app is running
    7. if (state == UIApplicationStateActive) {
    8. self.currentLaunchOptions = userInfo;
    9. //title, msg, ... anlegen
    10. [self showAlertForRemoteNotificationWith:title message:msg cancelTitle:@"Abbruch" okTitle:okTitle];
    11. }
    12. }
    13. #pragma mark - Remote Notification AlertView
    14. - (void) showAlertForRemoteNotificationWith: (NSString*) sTitle message: (NSString*) sMessage cancelTitle: (NSString*) sCancelTitle okTitle: (NSString*) sOkTitle{
    15. UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:sTitle
    16. message:sMessage
    17. delegate:nil
    18. cancelButtonTitle:sCancelTitle
    19. otherButtonTitles:sOkTitle, nil];
    20. alertView.delegate = self;
    21. [alertView show];
    22. }
    23. // Called when a button is clicked. The view will be automatically dismissed after this call returns
    24. - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    25. {
    26. MyViewController *mv = [[MyViewController alloc] initWithOptions: self.currentLaunchOptions];
    27. [[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:mv animated:NO completion:nil];
    28. [mv release];
    29. self.currentLaunchOptions = nil;
    30. }
    Alles anzeigen


    Der ViewController wird (modal) angezeigt und anschließend vom Nutzer wieder geschlossen. --> alles OK.
    Jetzt schicke ich die App in den Hintergrund und versende erneut eine Remote Notification und öffne die App per Klick auf die Notification. Die App stürzt mit der Meldung ab:

    Quellcode

    1. ​*** -[MyViewController respondsToSelector:]: message sent to deallocated instance 0x15b10800


    Die Bedeutung ist mir klar, allerdings verstehe ich die Ursache nicht. Um herauszufinden, wer eine Methode des bereits gelöschten MyViewControllers aufruft, habe ich die respondsToSelector() in MyViewController überschrieben:

    Quellcode

    1. ​- (BOOL)respondsToSelector:(SEL)aSelector {
    2. NSLog(@"MyViewController respondsToSelector %p %@", self, NSStringFromSelector(aSelector) );
    3. return [super respondsToSelector:aSelector];
    4. }


    Zusätzlich musste ich noch die 37. Zeile ([mv release];) entfernen, damit der ViewController nicht freigegeben wird. Nach Wiederholung der Prozedur erhalte ich folgende Log Meldung:

    Quellcode

    1. ​2014-11-25 18:44:38.444 testApp[643:132943] MyViewController respondsToSelector _isViewControllerInWindowHierarchy


    Was hat es mit der Methode isViewControllerInWindowHierarchy auf sich? Im Netz konnte ich nichts dazu finden.

    Jetzt das merkwürdige, erzeuge und präsentiere ich den ViewController direkt in der didReceiveRemoteNotification() (also ohne vorherige Alertabfrage) und wiederhole die Prozedur (mehrmals) bekomme ich keine Exception:

    Quellcode

    1. ​- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    2. UIApplicationState state = [application applicationState];
    3. if (state == UIApplicationStateActive) {
    4. MyViewController *mv = [[MyViewController alloc] initWithOptions: userInfo];
    5. [[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:mv animated:NO completion:nil];
    6. [mv release];
    7. }
    8. }


    Ist das ein Bug von iOS? Oder hat evtl. jemand eine Erklärung zum merkwürdigen Verhalten bei der Nutzung von einem UIAlertView?

    Gruß
    Stefan
  • stefan! schrieb:

    Was hat es mit der Methode isViewControllerInWindowHierarchy auf sich?

    Diese Methode ist privat. der Unterstrich am Beginn des Namens besagt sogar, dass sie ganz besonders privat ist. ;) Das hat auch nichts mit deinem Problem zu tun. Du hast einen Speicherverwaltungsfehler. Die Frage ist: Warum gibt die App deinen Viewcontroller frei?

    Das liegt wahrscheinlich am Rootviewcontroller: Wenn die App den nach der Delegatemethode freigibt, gibt sie auch deinen Viewcontroller frei. Welche Application-Delegate-Methoden ruft Cocoa Touch noch nach application:didReceiveRemoteNotification: auf?
    „Meine Komplikation hatte eine Komplikation.“
  • Thallius schrieb:

    Du arbeitest noch ohne ARC?

    Ja

    Die Frage ist: Warum gibt die App deinen Viewcontroller frei?

    Ich hatte vergessen zu erwähnen, dass die Fehlermeldung (Message-sent-to-deallocated-instance) sich auf die 1. Instanz des MyViewControllers bezieht. Da dieser (vom Nutzer) geschlossen wird, erfolgt die Freigabe der 1. Instanz --> passt also soweit.

    Das ganze passiert bei folgender Reihenfolge:
    1. App starten
    2. (1.) Push Notification empfangen application:didReceiveRemoteNotification: zeigt AlertView
    3. Nutzer bestätigt Alert --> MyViewController Instanz 1. erstellen (Adresse z.B. 0x14c3d600) und anschließend wieder schließen (per [self dismissViewControllerAnimated:YES completion:nil]; im MyViewController)
    4. App in den Hintergrund schicken
    5. (2.) Push Notification schicken und App per klick auf Notification öffnen
    6. Es wird die (leere) applicationWillEnterForeground:(UIApplication *)application aufgerufen
    7. Crash --> message sent to deallocated instance 0x14c3d600

    D.h. er kommt gar nicht bis zum Aufruf der application:didReceiveRemoteNotification: beim 2. öffnen der App (bzw. in den Vordergrund holen).
    mMn ist die Freigabe des 1. MyViewControllers korrekt, da dieser nicht mehr benötigt wird. Aber wer schickt diesem dann eine Nachricht beim erneuten öffnen der App?

    Welche Application-Delegate-Methoden ruft Cocoa Touch noch nach application:didReceiveRemoteNotification: auf?

    Wenn die App bereits aktiv ist wird keine Delegate Methode nach der application:didReceiveRemoteNotification: aufgerufen.
  • Jag mal den Analyzer drüber.
    Du hast da vermutlich ein gravierendes Speicherproblem.

    Man kann natürlich nur raten.

    Zum Einen empfiehlt Apple die Nutzung der Variante mit fetchCompletionHandler.
    -application:didReceiveRemoteNotification:fetchCompletionHandler:
    Durch den Handler bist Du dann relativ unabhängig von irgendwelchen Annahmen Deines Kontexts.

    Ansonsten scheint irgendetwas (eventuell irgend ein Delegate des MyViewController) noch an dem zu hängen und damit zu kommunizieren.
    In dem Fall kann Dir das Analyze Tool helfen.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • stefan! schrieb:

    Wieso geht es ohne AlertView problemlos?

    Das kannst nur Du herausfinden.
    Ist eventuell Deine erste Instanz als Delegate des AlertView registriert worden und das Ding will darauf noch zugreifen?
    Versuch mal testweise statt eines Delegates einen Block.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P