Я получил этот отчет о сбое, но я не знаю, как его отладить.
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
Версия iOS 7.0.3. Кто-нибудь испытал эту странную аварию?
ОБНОВИТЬ:
Я не знаю, где в моем коде произошел этот сбой, поэтому я не могу опубликовать код здесь, извините.
Второе ОБНОВЛЕНИЕ
Смотрите ответ ниже.
ios
iphone
objective-c
Арнольд
источник
источник
Ответы:
Я размышляю, основываясь на чем-то похожем, что я недавно отлаживал ... если вы нажимаете (или выдвигаете) контроллер представления с помощью Animated: ДА, он не завершается сразу же, и происходят плохие вещи, если вы делаете еще одно нажатие или высовываете перед анимацией завершается. Вы можете легко проверить, действительно ли это так, временно изменив операции Push и Pop на Animated: NO (чтобы они выполнялись синхронно) и посмотрев, устраняет ли это сбой. Если это действительно ваша проблема, и вы хотите снова включить анимацию, то правильная стратегия - реализовать протокол UINavigationControllerDelegate. Это включает в себя следующий метод, который вызывается после завершения анимации:
По сути, вы хотите переместить некоторый код по мере необходимости в этот метод, чтобы гарантировать, что никакие другие действия, которые могут вызвать изменение в стеке NavigationController, не будут выполняться, пока анимация не будет завершена и стек не будет готов к дополнительным изменениям.
источник
[newViewController setLabelTitle:...]
сразу после вызова pushViewController с помощьюAnimated:YES.
И я решил переместить метод setLabelTitle в viewDidLoad на новом ViewViewController. Спасибо, что дали мне подсказку.Мы также начали сталкиваться с этой проблемой, и, скорее всего, наша проблема была вызвана той же проблемой.
В нашем случае нам приходилось извлекать данные из серверной части в некоторых случаях, что означало, что пользователь может что-то нажать, и тогда перед навигацией будет небольшая задержка. Если пользователь быстро переключается, он может получить два навигационных нажатия от одного и того же контроллера представления, что вызвало именно это исключение.
Наше решение - это категория в UINavigationController, которая предотвращает нажатия / всплывающие сообщения, если только верхний vc не является тем же самым в данный момент времени.
.h файл:
.m файл:
Пока что это, похоже, решило проблему для нас. Пример:
По сути, правило таково: перед любыми задержками, не связанными с пользователем, захватите блокировку у соответствующего контроллера Nav и включите ее в вызов push / pop.
Слово «блокировка» может быть слегка некачественным, поскольку оно может указывать на наличие какой-либо формы блокировки, требующей разблокировки, но, поскольку нигде нет метода «разблокировки», вероятно, все в порядке.
(Как примечание, «не связанные с пользователем задержки» - это любые задержки, вызываемые кодом, то есть что-либо асинхронное. Пользователи, нажимающие на контроллер Nav, который анимированно толкается, не учитываются, и для них не нужно делать версию navigationLock: version). случаев.)
источник
Этот код решает проблему: https://gist.github.com/nonamelive/9334458
Он использует частный API, но я могу подтвердить, что он безопасен в App Store. (Одно из моих приложений, использующих этот код, было одобрено App Store.)
источник
Я опишу более подробную информацию об этой аварии в моем приложении и пометить это как ответ.
Мое приложение имеет UINavigationController с корневым контроллером UITableViewController, который содержит список объектов заметок. Объект заметки имеет свойство содержимого в html. Выбор заметки перейдет в детальный контроллер.
Детальный контроллер
Этот контроллер имеет UIWebView, отображать содержимое заметки, переданной от корневого контроллера.
Этот контроллер является делегатом элемента управления webview. Если заметка содержит ссылки, нажмите на ссылку, чтобы перейти в веб-браузер приложения.
Я получал выше отчет о сбое каждый день. Я не знаю, где в моем коде произошел этот сбой. После некоторых исследований с помощью пользователя, я наконец смог исправить эту ошибку. Этот HTML-контент вызовет сбой:
В методе viewDidLoad подробного контроллера я загрузил этот html в элемент управления webview, сразу после этого вышеупомянутый метод делегата был вызван немедленно с request.URL - источник iframe (google.com). Этот метод делегата вызывает метод pushViewController, находясь в viewDidLoad => crash!
Я исправил этот сбой, проверив навигационный тип:
Надеюсь это поможет
источник
viewDidLoad
?У меня была та же проблема, что просто работало для меня, менял Animated: Yes на Animated: No.
Похоже, проблема была в том, что анимация не была завершена вовремя.
Надеюсь, это кому-нибудь поможет.
источник
Чтобы воспроизвести эту ошибку, попробуйте нажать два контроллера вида одновременно. Или толкать и высовывать одновременно. Пример:
Я создал категорию, которая перехватывает эти вызовы и делает их безопасными, следя за тем, чтобы никаких других нажатий не происходило во время выполнения. Просто скопируйте код в свой проект, и из-за метода метания вам будет хорошо.
источник
popToRootViewController
илиpopToViewController:
когда вы уже подключены к корневому контроллеру представления или к viewController, тоdidShowViewController
не будут вызываться и будут зависатьviewTransitionInProgress
.self.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)viewController; [self.interactivePopGestureRecognizer setEnabled:YES];
Когда был отключен распознаватель? А откуда вы знаете, каким должен быть делегат? С этими строками, для меня это ломает поп-жест после щелчка один раз.Только что столкнулся с этой проблемой. Позвольте мне показать вам мой код:
Ошибка появляется из-за этой строки:
Вы не можете добавить себя в подпредставление. Я изменил строку кода на:
Ошибка ушла, и я смог увидеть оба мнения. Просто подумал, что это поможет любому, кто хочет увидеть пример.
источник
Найдите в вашем коде «addSubview».
В одном из мест, где вы вызывали этот метод, вы пытались добавить представление в его собственный массив подвидов, используя этот метод.
Например:
Или:
источник
[View2.view addSubview:View2.view]
таким образом, добавив self в качестве subview.Я думаю, что нажатие / выталкивание контроллеров представления с анимацией в любой момент должно быть прекрасно, и SDK должен любезно обработать очередь вызовов для нас.
Следовательно, это не так, и все решения пытаются игнорировать последующие изменения, что можно считать ошибкой, поскольку окончательный стек навигации не соответствует предназначению кода.
Вместо этого я реализовал очередь push-вызовов:
Он не обрабатывает смешанные очереди push и pops, но это хороший старт для исправления большинства наших сбоев.
Суть: https://gist.github.com/rivera-ernesto/0bc628be1e24ff5704ae
источник
Извините за опоздание на вечеринку. У меня недавно была эта проблема, когда моя навигационная панель переходила в поврежденное состояние из-за одновременного нажатия более одного контроллера представления. Это происходит потому, что другой контроллер представления перемещается, пока первый контроллер представления все еще анимируется. Взяв подсказку из неамелевского ответа, я нашел простое решение, которое работает в моем случае. Вам просто нужно создать подкласс
UINavigationController
и переопределить метод pushViewController и проверить, завершена ли предыдущая анимация контроллера представления. Вы можете прослушать завершение анимации, сделав свой класс делегатомUINavigationControllerDelegate
и задав для него делегатself
.Я загрузил суть здесь, чтобы все было просто.
Просто убедитесь, что вы установили этот новый класс как NavigationController в вашей раскадровке.
источник
Основываясь на замечательном совете @RobP, я создал подкласс UINavigationController , чтобы избежать подобных проблем. Он обрабатывает нажатия и / или нажатия, и вы можете безопасно выполнить:
Если 'acceptConflictingCommands' помечает его как истинное (по умолчанию), пользователь увидит анимированное нажатие vc1, vc2, vc3, а затем увидит анимированный щелчок vc3. Если значение acceptConflictingCommands равно false, все запросы push / pop будут отбрасываться до тех пор, пока vc1 не будет полностью передан - следовательно, остальные 3 вызова будут отброшены.
источник
animated:true
флагом?Решение nonamelive является удивительным. Но если вы не хотите использовать частный API, вы можете просто достичь
UINavigationControllerDelegate
метода. Или вы можете изменить анимациюYES
наNO
. Вот пример кода, вы можете наследовать его. Надеюсь, это полезно :)https://github.com/antrix1989/ANNavigationController
источник
Я много раз искал эту проблему, возможно, она выдвигает два или более VC одновременно, что вызывает проблему с анимацией, вы можете сослаться на это: Can't Add Self as Subview 崩溃 解决 办法
просто убедитесь, что есть один VC на переходный процесс одновременно, удачи.
источник
Иногда вы по ошибке пытались добавить представление к собственному представлению.
измените это на ваш подвид.
источник
Я также столкнулся с этой проблемой. Когда я сделал анализ журнала Firebase, я обнаружил, что эта проблема возникает только при холодном запуске приложения. Поэтому я написал демо, которое может воспроизвести этот сбой.
,
Я также обнаружил, что при отображении корневого viewcontroller окна выполнение нескольких нажатий больше не вызовет той же проблемы. (Вы можете комментировать testColdStartUp (rootNav) в AppDelegate.swift и раскомментировать комментарий testColdStartUp () в ViewController.swift)
PS: я проанализировал сцену этого сбоя в моем приложении. Когда пользователь нажимает push-уведомление для холодного запуска приложения, приложение все еще находится на странице Launch и нажимает еще один push для перехода. В это время в приложении может появиться Crash. Мое текущее решение - кэшировать принудительный запуск или «холодный» запуск универсальной ссылки, чтобы открыть страницу перехода приложения, дождаться отображения rootviewcontroller и затем отложить выполнение.
источник
попробуйте навигацию, используя метод задержки, для завершения последней анимации навигации,
[self performSelector:<#(SEL)#> withObject:<#(id)#> afterDelay:<#(NSTimeInterval)#>]
источник
Представление не может быть добавлено в качестве подпредставления само по себе.
Представления поддерживают иерархию «родитель-потомок», поэтому, если вы добавляете представление как подпредставление само по себе, оно будет происходить через исключение.
если класс UIViewController, то чтобы получить его представление, вы используете self.view.
если класс UIView Class, то чтобы получить его представление, вы используете self.
источник
Вы не можете добавить себя как подпредставление, если это будет класс UiViewController. Вы можете добавить себя как подпредставление, если это будет класс UiView.
источник
Если вы хотите добавить Subview к View, вы можете сделать это следующим образом;
источник