J'ai reçu ce rapport d'erreur, mais je ne sais pas comment le déboguer.
Fatal Exception NSInvalidArgumentException
Can't add self as subview
0 ... CoreFoundation __exceptionPreprocess + 130
1 libobjc.A.dylib objc_exception_throw + 38
2 CoreFoundation -[NSException initWithCoder:]
3 UIKit -[UIView(Internal) _addSubview:positioned:relativeTo:] + 110
4 UIKit -[UIView(Hierarchy) addSubview:] + 30
5 UIKit __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke + 1196
6 UIKit +[UIView(Animation) performWithoutAnimation:] + 72
7 UIKit -[_UINavigationParallaxTransition animateTransition:] + 732
8 UIKit -[UINavigationController _startCustomTransition:] + 2616
9 UIKit -[UINavigationController _startDeferredTransitionIfNeeded:] + 418
10 UIKit -[UINavigationController __viewWillLayoutSubviews] + 44
11 UIKit -[UILayoutContainerView layoutSubviews] + 184
12 UIKit -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 346
13 QuartzCore -[CALayer layoutSublayers] + 142
14 QuartzCore CA::Layer::layout_if_needed(CA::Transaction*) + 350
15 QuartzCore CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 16
16 QuartzCore CA::Context::commit_transaction(CA::Transaction*) + 228
17 QuartzCore CA::Transaction::commit() + 314
18 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 56
La version iOS est 7.0.3. Quelqu'un a-t-il vécu ce crash étrange?
METTRE À JOUR:
Je ne sais pas où dans mon code a causé ce plantage, donc je ne peux pas poster le code ici, désolé.
Deuxième MISE À JOUR
Voir la réponse ci-dessous.
ios
iphone
objective-c
Arnol
la source
la source
Réponses:
Je spécule sur la base de quelque chose de similaire que j'ai débogué récemment ... si vous poussez (ou pop) un contrôleur de vue avec Animated: OUI cela ne se termine pas tout de suite, et de mauvaises choses se produisent si vous faites un autre push ou pop avant l'animation se termine. Vous pouvez facilement tester si c'est effectivement le cas en modifiant temporairement vos opérations Push et Pop en Animated: NO (afin qu'elles se terminent de manière synchrone) et voir si cela élimine le crash. Si c'est effectivement votre problème et que vous souhaitez réactiver l'animation, la stratégie correcte consiste à implémenter le protocole UINavigationControllerDelegate. Cela inclut la méthode suivante, qui est appelée une fois l'animation terminée:
Fondamentalement, vous souhaitez déplacer du code selon les besoins dans cette méthode pour vous assurer qu'aucune autre action susceptible de provoquer une modification de la pile NavigationController ne se produira jusqu'à ce que l'animation soit terminée et que la pile soit prête pour d'autres modifications.
la source
[newViewController setLabelTitle:...]
interface utilisateur du nouveau contrôleur de vue juste après avoir appelé pushViewController avecAnimated:YES.
Et j'ai résolu le déplacement de la méthode setLabelTitle vers viewDidLoad sur le newViewController. Merci de m'avoir donné l'indice.Nous avons également commencé à avoir ce problème, et il est fort probable que le nôtre soit causé par le même problème.
Dans notre cas, nous devions extraire des données du back-end dans certains cas, ce qui signifiait qu'un utilisateur pouvait appuyer sur quelque chose, puis il y avait un léger délai avant que la poussée de navigation se produise. Si un utilisateur tapait rapidement, il pourrait se retrouver avec deux poussées de navigation du même contrôleur de vue, ce qui a déclenché cette exception.
Notre solution est une catégorie sur le UINavigationController qui empêche les poussées / pops à moins que le vc supérieur ne soit le même à partir d'un moment donné.
fichier .h:
Fichier .m:
Jusqu'à présent, cela semble avoir résolu le problème pour nous. Exemple:
Fondamentalement, la règle est la suivante: avant tout retard non lié à l'utilisateur, saisissez un verrou du contrôleur de navigation concerné et incluez-le dans l'appel à push / pop.
Le mot "verrouiller" peut être une formulation légèrement médiocre car il peut insinuer qu'il existe une forme de verrouillage qui doit être déverrouillée, mais comme il n'y a pas de méthode de "déverrouillage" nulle part, c'est probablement correct.
(En remarque, les "retards non liés à l'utilisateur" sont tous les retards que le code provoque, c'est-à-dire tout ce qui est asynchrone. Les utilisateurs qui tapent sur un contrôleur de navigation qui est poussé de manière animée ne comptent pas et il n'est pas nécessaire de faire le navigationLock: version pour ceux-ci cas.)
la source
Ce code résout le problème: https://gist.github.com/nonamelive/9334458
Il utilise une API privée, mais je peux confirmer que c'est sûr App Store. (Une de mes applications utilisant ce code a été approuvée par l'App Store.)
la source
Je décrirai plus de détails sur ce crash dans mon application et marquerai ceci comme répondu.
Mon application a un UINavigationController avec le contrôleur racine est un UITableViewController qui contient une liste d'objets de note. L'objet note a une propriété content en html. Sélectionnez une note qui ira au contrôleur de détail.
Contrôleur de détail
Ce contrôleur a un UIWebView, affiche le contenu de la note transmis par le contrôleur racine.
Ce contrôleur est le délégué du contrôle Webview. Si la note contient des liens, appuyez sur un lien pour accéder au navigateur Web intégré à l'application.
J'ai reçu le rapport de plantage ci-dessus tous les jours. Je ne sais pas où dans mon code a causé ce plantage. Après quelques recherches avec l'aide d'un utilisateur, j'ai finalement pu résoudre ce crash. Ce contenu html provoquera le crash:
Dans la méthode viewDidLoad du contrôleur de détail, j'ai chargé ce code HTML dans le contrôle Webview, juste après cela, la méthode de délégation ci-dessus a été appelée immédiatement avec request.URL est la source de l'iframe (google.com). Cette méthode déléguée appelle la méthode pushViewController pendant que dans viewDidLoad => crash!
J'ai corrigé ce crash en vérifiant le navigationType:
J'espère que cela t'aides
la source
viewDidLoad
?J'ai eu le même problème, ce qui a simplement fonctionné pour moi était de changer Animé: Oui en Animé: Non.
Il semble que le problème soit dû au fait que l'animation ne s'est pas terminée à temps.
J'espère que cela aide quelqu'un.
la source
Pour reproduire ce bogue, essayez de pousser deux contrôleurs de vue en même temps. Ou pousser et sauter en même temps. Exemple:
J'ai créé une catégorie qui intercepte ces appels et les rend sûrs en m'assurant qu'aucune autre poussée ne se produit pendant qu'un est en cours. Copiez simplement le code dans votre projet et en raison du changement de méthode, vous serez prêt à partir.
la source
popToRootViewController
oupopToViewController:
lorsque vous êtes déjà sur le contrôleur de vue racine ou sur le viewController, ildidShowViewController
ne sera pas appelé et il sera bloquéviewTransitionInProgress
.self.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)viewController; [self.interactivePopGestureRecognizer setEnabled:YES];
Quand le module de reconnaissance a-t-il été désactivé? Et comment savez-vous ce que devrait être le délégué? Avec ces lignes, pour moi, cela brise le geste pop après avoir sauté une fois.Je viens de rencontrer ce problème également. Laissez-moi vous montrer mon code:
L'erreur survient à cause de cette ligne:
Vous ne pouvez pas vous ajouter à la sous-vue. J'ai changé la ligne de code en:
L'erreur a disparu et j'ai pu voir les deux vues. Je pensais juste que cela aiderait tous ceux qui voulaient voir un exemple.
la source
Recherchez dans votre code "addSubview".
Dans l'un des endroits où vous avez appelé cette méthode, vous avez essayé d'ajouter une vue à son propre tableau de sous-vues à l'aide de cette méthode.
Par exemple:
Ou:
la source
[View2.view addSubview:View2.view]
ainsi, l'ajout de soi en tant que sous-vue.Je pense que pousser / sauter des contrôleurs de vue avec une animation à tout moment devrait être parfaitement bien et que le SDK devrait gérer gracieusement la file d'attente des appels pour nous.
Par conséquent, ce n'est pas le cas et toutes les solutions essaient d'ignorer les poussées ultérieures, ce qui pourrait être considéré comme un bogue puisque la pile de navigation finale n'est pas ce que le code voulait.
J'ai mis en place une file d'attente d'appels push à la place:
Il ne gère pas les files d'attente mixtes de push et de pop, mais c'est un bon démarreur pour résoudre la plupart de nos plantages.
Gist: https://gist.github.com/rivera-ernesto/0bc628be1e24ff5704ae
la source
Désolé d'être en retard pour la fête. J'ai récemment eu ce problème dans lequel ma barre de navigation entre dans un état corrompu en poussant plus d'un contrôleur de vue en même temps. Cela se produit car l'autre contrôleur de vue est poussé alors que le premier contrôleur de vue est toujours en cours d'animation. Faisant allusion à la réponse non amélive, j'ai trouvé ma solution simple qui fonctionne dans mon cas. Vous avez juste besoin de sous-classer
UINavigationController
-classer et de remplacer la méthode pushViewController et de vérifier si l'animation précédente du contrôleur de vue est encore terminée. Vous pouvez écouter la fin de l'animation en faisant de votre classe un déléguéUINavigationControllerDelegate
et en définissant le délégué surself
.J'ai téléchargé l'essentiel ici pour simplifier les choses.
Assurez-vous simplement de définir cette nouvelle classe comme NavigationController dans votre storyboard.
la source
Basé sur le bon indice @RobP, j'ai créé la sous-classe UINavigationController afin d'éviter de tels problèmes. Il gère la poussée et / ou le popping et vous pouvez exécuter en toute sécurité:
Si le drapeau 'acceptConflictingCommands' est vrai (par défaut), l'utilisateur verra un push animé de vc1, vc2, vc3 puis verra un pop-up animé de vc3. Si 'acceptConflictingCommands' est faux, toutes les requêtes push / pop seront rejetées jusqu'à ce que vc1 soit complètement poussé - donc les 3 autres appels seront rejetés.
la source
animated:true
indicateur?La solution de nonamelive est géniale. Mais si vous ne souhaitez pas utiliser l'API privée, vous pouvez simplement
UINavigationControllerDelegate
utiliser la méthode ou changer l'animationYES
enNO
. Voici un exemple de code, vous pouvez en hériter. J'espère que c'est utile :)https://github.com/antrix1989/ANNavigationController
la source
J'avais beaucoup cherché ce problème, cela poussait peut-être deux VC ou plus en même temps, ce qui causait le problème d'animation de poussée, vous pouvez vous référer à ceci: Impossible de s'ajouter en tant que sous-vue 崩溃 解决 办法
assurez-vous simplement qu'il y a un VC sur la progression de la transition en même temps , bonne chance.
la source
Parfois, vous avez essayé par erreur d'ajouter une vue à sa propre vue.
changez ceci en votre vue secondaire.
la source
J'ai également rencontré ce problème. Lorsque j'ai effectué l'analyse du journal Firebase, j'ai constaté que ce problème ne se produit que lorsque l'application est démarrée à froid. J'ai donc écrit une démo qui peut reproduire ce crash.
.
J'ai également constaté que lorsque le viewcontroller racine de la fenêtre est affiché, effectuer plusieurs poussées ne causera plus le même problème. (Vous pouvez commenter testColdStartUp (rootNav) dans AppDelegate.swift et décommenter le commentaire testColdStartUp () dans ViewController.swift)
ps: J'ai analysé la scène de ce crash dans mon application. Lorsque l'utilisateur clique sur la notification push pour démarrer l'application à froid, l'application est toujours sur la page de lancement et clique sur un autre push pour sauter. À ce moment, l'application peut apparaître le Crash. Mon courant La solution consiste à mettre en cache le démarrage à froid push ou Universal Link pour ouvrir la page de saut de l'application, attendre que le rootviewcontroller s'affiche, puis retarder l'exécution.
la source
essayez votre navigation en utilisant la méthode de retard, pour terminer la dernière animation de navigation,
[self performSelector:<#(SEL)#> withObject:<#(id)#> afterDelay:<#(NSTimeInterval)#>]
la source
Une vue ne peut pas être ajoutée en tant que sous-vue en elle-même.
Les vues maintiennent une hiérarchie parent-enfant, donc si vous ajoutez une vue en tant que sous-vue en elle-même, elle passera par exception.
si une classe est UIViewController, vous utilisez self.view pour obtenir sa vue.
si une classe est UIView Class, vous utilisez self pour obtenir sa vue.
la source
vous ne pouvez pas ajouter self en tant que sous-vue s'il s'agit d'une classe UiViewController. vous pouvez ajouter self en tant que sous-vue s'il s'agit d'une classe UiView.
la source
Si vous souhaitez ajouter une sous-vue à une vue, vous pouvez le faire comme ceci;
la source