- Vue-Contrôleur envoyé un message, même si il a été libéré
Je ne suis pas sûr si quelque chose a changé dans le SDK de l'iPhone 3.0, mais je suis le plus étrange erreur. J'ai une vue contrôleur de hiérarchie où je basculer entre la vue des contrôleurs en fonction de l'interface de l'orientation. À partir de ce que je peux dire, l'erreur est provoquée à chaque fois que je tourne l'interface a-vue-contrôleur qui a été libéré est envoyé un shouldAutorotateToInterfaceOrientation message. C'est la trace de l'erreur:
#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
L'erreur qui est imprimé sur la Console de Débogage avec NSZombieEnabled est:
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
Ce que je ne peux pas comprendre, c'est pourquoi le système est en train d'essayer de message de ce contrôleur, même si il a été libéré et est-il un moyen pour indiquer au système que le contrôleur n'existe plus.
[Mise à JOUR]:
J'ai mis en place un exemple de projet de la réplication du bug: télécharger
Charge de l'application, puis de changer le Simulateur de l'orientation un peu de temps de Paysage à Portrait et il devrait se produire. J'ai essayé le même morceau de code sur le téléphone et il se comporte exactement de la même façon, donc ce n'est pas un simulateur de question connexe.
[Mise à JOUR]:
J'ai utilisé une de mes demandes de support technique Apple pour voir si ils peuvent m'aider à aller au fond de cette. Va poster la solution - si elles en ont un, ici. Merci pour l'aide pour l'instant.
OriginalL'auteur Michael Gaylord | 2009-10-18
Vous devez vous connecter pour publier un commentaire.
De toute évidence, le contrôleur est toujours enregistré pour la notification en question. envoyez -removeObserver:auto pour le centre de notification dans votre méthode dealloc.
Ce qui se passe pendant le traitement de la notification, et non à l'envoi de l'avis lui-même. Me semble plus comme le délégué ou le contrôleur a été libéré sans d'abord vous déconnecter de l'INTERFACE utilisateur.
Le postNotificationName:objet:userInfo ligne de la trace de la pile n'est pas d'accord fortement avec bbum de l'évaluation. Lorsque vous envoyez une notification par défaut, la notification du gestionnaire d'appels d'auditeurs tout de suite, avant que le poste d'appel, même de retour...
La chose étrange, c'est que la notification est envoyé à partir du système sous-jacent. Donc je n'ai pas enregistré le contrôleur de la notification. L'ajout de removeObserver:auto ne vous aide pas, malheureusement.
Ce n'est pas la notification qui est le problème, mais le traitement de la notification la notification est déjà livré à cet backtrace). Plus précisément, c'est de s'écraser en essayant d'appeler respondsToSelector: est beaucoup plus typique d'un délégué ou délégué-comme le modèle. I. e. vous pourrait très probablement déclencher le même incident sans un avis dans le backtrace en manipulant directement la UIWindow.
OriginalL'auteur NSResponder
Donc après une semaine d'attente, Apple Developer Support Technique a réussi à m'aider à trier mon problème. Voici leur réponse:
Ce que j'ai fait a l'aide d'un super-vue-contrôleur qui a présenté et a rejeté la vue des contrôleurs. Plutôt que de permutation de vue des contrôleurs et en retirant les points de vue à l'aide de l'AppDelegate.
C'était à peu près l'ensemble de l'e-mail. Je pourrais avoir suivi plus loin, mais elle l'a fait à la fin de résoudre mon problème. Je soupçonne que la raison pour laquelle il a changé en 3.0 avait quelque chose à faire avec améliorations de performances.
OriginalL'auteur Michael Gaylord
Beaucoup de confusion ici... voyons voir si cela aide:
Alors que la désallocation détruit l'instance d'un objet, il ne détruit pas les références aux instances. Avec Zombie activer la détection, de libération de la mémoire provoque l'exécution de substituer un zombie pour l'instance. Le zombie puis détecte et enregistre quand il est messaged.
La raison pour laquelle cela se produit est parce que l'objet a été libéré sans supprimer toutes les références à l'objet de l'application de l'objet graphique. Dans ce cas, il semble que la désalloué contrôleur n'a jamais été unset en tant que contrôleur de la UIWindow instance.
Qui est, le traitement de la notification est un hareng rouge. Dans cette trace, l'avis a déjà été livrés et UIWindow est dans le milieu de traitement. Ainsi, le problème est quelque part entre les UIWindow et à votre application. Très probablement, votre objet a été libéré avant d'être retiré de la fenêtre contrôleur ou de son délégué.
Avant que votre programme est vraiment fait avec un objet -- avant de vous envoyer le dernier
-release
appel des soldes de la dernière existante-retain
votre application causé ou appelé -- vous devez vous assurer que toutes les références faibles à l'objet sont détruits. Par exemple, si votre objet est le délégué d'un UIWindow, assurez-vous de définir le délégué de la fenêtre pournil
(ou un autre objet) avant l'envoi de ce dernier-release
.Maintenant, dans ce cas, il peut aussi être tout simplement que vous avez plus libéré et de l'objet. Vous pourriez encore besoin de l'objet, mais un supplément de
-release
ou-autorelease
, quelque part, en l'amenant à être détruits avant que vous ont été faites avec.Quand il y a des références à une désallocation de l'objet, une panne peut se produire chaque fois que quelque chose essaie de lui envoyer un message. Dans votre cas, il se passe lorsque les changements d'orientation.
OriginalL'auteur bbum
Si quelqu'un se soucie encore, une solution simple est de créer une vue de la racine contrôleur + vue qui ne change jamais.
Donné SomeViewController + SomeView Un, et SomeViewController + SomeView B, si vous ajoutez Une vue de la fenêtre comme une sous-vue, puis ajouter une vue B comme une sous-vue et de suppression de vue, l'application crash sur faire pivoter.
Pour éviter le crash, créer un générique UIViewController + UIView X, et ajouter X vue de la fenêtre comme une sous-vue. Ajouter et supprimer des points de vue de A et de B vers/à partir de X vue, pas de la fenêtre directement. L'application va plus tomber en panne.
Noter qu'il ne suffit pas d'ajouter une vue de la fenêtre, vous devez ajouter un point de vue qui offre une vue contrôleur.
OriginalL'auteur Mark Smith
C'est une bonne raison pour définir la
ToolbarController = nil
après l'avoir relâché. Il est sûr d'envoyer des messages à néant, mais de ne pas les adresses de désalloué objets. Dans ce cas, votre envoi d'un message à une adresse d'un objet qui n'est pas sortie, qui est à l'origine d'un accident.C'est une perte de temps pour vérifier la
ToolbarController != nil
avant d'envoyer le message, parce que si c'est nul, que vous pouvez envoyer le message en toute sécurité. si elle n'est pas nulle et valide, elle sera de retour OUI ou NON. Mais si c'est un pointeur vers désallocation de la mémoire (comme vous semblez avoir ici) il va crash de toute façon.Presque assurément totalement étrangères. L'objet est toujours inscrit pour recevoir des notifications même si il est libéré.
OriginalL'auteur Abizern
J'ai rencontré ce problème ainsi. L'ordre des événements est:
(1) créer l'application unique de UIWindow objet
(2) ajouter une sous-vue qui est géré par une-vue-contrôleur à la fenêtre
(3) suppression de la première vue et en ajouter un nouveau
Si j'ai faites pivoter l'appareil par la suite, l'application se bloque en raison d'un message envoyé à la désalloué-vue-contrôleur. (Eh bien, c'est en fait de l'envoyer à un sous-contrôleur de la première-vue-contrôleur.) Il essaye d'envoyer -[respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)].
Si votre application s'exécute uniquement en mode portrait, vous pouvez prendre le problème par l'ajout d'une catégorie à UIWindow qui remplace _shouldAutorotateToInterfaceOrientation: pour retourner pour tout autre que le mode portrait.
Évidemment, ce n'est pas une véritable solution. J'ai double-triple-vérifié mon code et je ne vois aucune raison pourquoi la fenêtre doit être l'envoi de ce message pour le contrôleur de vue qui a été retiré de l'écran et libéré. Ce problème semble être apparu dans la version 3.0, et pas avant. Peut-être que je suis en train de faire quelque chose de stupide, mais il semble vraiment y avoir quelque chose d'étrange ici à l'œuvre.
Le dépôt d'un rapport de bogue avec un petit cas de test serait une bonne idée.
J'ai ajouté un lien vers un exemple de projet en reproduisant le problème. Vous pouvez trouver le lien au bas de la description ci-dessus.
Soumettre un rapport de bogue et de joindre l'exemple de projet.
OriginalL'auteur Mark Smith
J'ai également eu le même problème, mais n'était pas en mesure de laisser un contrôleur de traîner comme Mark Smith suggestion. Retrait de la vue-contrôleur avec autorelease plutôt que de la libération ou de la conservation d'un bien qui semblait faire l'affaire.
Semble que le parent UIWindow/cadre a besoin de la vue-contrôleur de traîner un peu plus longtemps pour lui permettre de retirer le délégué lien.
OriginalL'auteur gazreese
J'avais connu le même problème jusqu'à supprimé certains 'cogner' lignes de code que j'ai utilisé pour pousser l'animation comme ceux:
UIView* superv = navigationController.view.superview;
[navigationController.view removeFromSuperview];
[superv addSubview:navigationController.view];
Certainement, le ci-dessus est 'casser' le chemin à parcourir depuis la version 3.0 SDK avait été publié par Apple. J'ai été forcé d'utiliser le push/pop approche à la place. N'ai pas le problème avec les 2.x ainsi. Assurez-vous de ne pas avoir quelque chose de similaire dans votre code.
De l'espoir, ça aide.
À certains égards, vous avez eu raison, ici. J'ai fini par utiliser la presentModalViewController méthode qui a très bien fonctionné. Au lieu d'une manette de navigation à pousser et à éclater de contrôleurs.
OriginalL'auteur Mike Orlov
J'ai posté une réponse ici:
https://stackoverflow.com/a/19237139/539149
J'ai eu une place qui a dit:
Qui a causé de la version à être appelé deux fois (si la mémoire a été libérée immédiatement), mais le zombie n'est pas révélé jusqu'à ce qu'un objet possédé par iOS essayé de faire référence à l'objet plus tard dans le thread principal.
OriginalL'auteur Zack Morris