Recebi este relatório de falha, mas não sei como depurá-lo.
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
A versão do iOS é 7.0.3. Alguém experimentou esse acidente estranho?
ATUALIZAR:
Não sei onde no meu código causou essa falha, por isso não posso postar o código aqui, desculpe.
Segunda ATUALIZAÇÃO
Veja a resposta abaixo.
ios
iphone
objective-c
Arnol
fonte
fonte
Respostas:
Estou especulando com base em algo semelhante que depurei recentemente ... se você enviar (ou abrir) um controlador de exibição com o Animated: SIM, ele não será concluído imediatamente, e coisas ruins acontecerão se você fizer outro envio ou envio antes da animação completa. Você pode facilmente testar se esse é realmente o caso, alterando temporariamente suas operações Push e Pop para Animated: NO (para que elas sejam concluídas de forma síncrona) e ver se isso elimina a falha. Se esse é realmente o seu problema e você deseja ativar a animação novamente, a estratégia correta é implementar o protocolo UINavigationControllerDelegate. Isso inclui o seguinte método, chamado após a conclusão da animação:
Basicamente, você deseja mover algum código conforme necessário para esse método para garantir que nenhuma outra ação que possa causar uma alteração na pilha NavigationController ocorra até que a animação seja concluída e a pilha esteja pronta para mais alterações.
fonte
[newViewController setLabelTitle:...]
usuário do novo controlador de exibição logo após chamar pushViewController comAnimated:YES.
E resolvi mover o método setLabelTitle para viewDidLoad no newViewController. Obrigado por me dar a pista.Também começamos a solucionar esse problema, e era muito provável que as nossas fossem causadas pelo mesmo problema.
Em nosso caso, tivemos que extrair dados do back-end em alguns casos, o que significava que um usuário poderia tocar em algo e, em seguida, haveria um pequeno atraso antes da ocorrência do push de navegação. Se um usuário estivesse digitando rapidamente, ele poderia acabar com dois push de navegação do mesmo controlador de exibição, o que desencadeou essa mesma exceção.
Nossa solução é uma categoria no UINavigationController que evita empurrões / pops, a menos que o vc superior seja o mesmo em um determinado momento.
arquivo .h:
arquivo .m:
Até agora, isso parece ter resolvido o problema para nós. Exemplo:
Basicamente, a regra é: antes de qualquer atraso não relacionado ao usuário pegue um bloqueio do controlador de navegação relevante e inclua-o na chamada para push / pop.
A palavra "bloqueio" pode ter uma formulação um pouco ruim, pois pode indicar que há alguma forma de bloqueio que precisa ser desbloqueada, mas como não há um método de "desbloqueio" em qualquer lugar, provavelmente tudo bem.
(Como uma nota lateral, "atrasos não relacionados ao usuário" são quaisquer atrasos que o código está causando, ou seja, qualquer coisa assíncrona. Os usuários que tocam em um controlador nav que é animado animadamente não contam e não é necessário executar o navigationLock: version para esses casos).
fonte
Este código resolve o problema: https://gist.github.com/nonamelive/9334458
Ele usa uma API privada, mas posso confirmar que é seguro na App Store. (Um dos meus aplicativos usando esse código foi aprovado pela App Store.)
fonte
Descreverei mais detalhes sobre essa falha no meu aplicativo e marcarei isso como respondido.
Meu aplicativo tem um UINavigationController com o controlador raiz. É um UITableViewController que contém uma lista de objetos de anotação. O objeto de nota possui uma propriedade de conteúdo em html. Selecione uma nota para o controlador de detalhes.
Controlador de detalhes
Este controlador possui um UIWebView, exibe o conteúdo da nota passado no controlador raiz.
Este controlador é o delegado do controle de visualização na web. Se a nota contiver links, toque em um link para o navegador do aplicativo.
Recebi o relatório de falha acima todos os dias. Não sei onde no meu código causou essa falha. Depois de algumas investigações com a ajuda de um usuário, finalmente pude consertar essa falha. Este conteúdo html causará a falha:
No método viewDidLoad do controlador de detalhes, carreguei esse html no controle webview, logo depois, o método delegado acima foi chamado imediatamente com request.URL é a fonte do iframe (google.com). Este método delegado chama o método pushViewController enquanto em viewDidLoad => travamento!
Corrigi essa falha verificando o navigationType:
Espero que isto ajude
fonte
viewDidLoad
?Eu tive o mesmo problema, o que simplesmente funcionou para mim foi mudar Animated: Yes para Animated: No.
Parece que o problema ocorreu devido à animação não ser concluída a tempo.
Espero que isso ajude alguém.
fonte
Para reproduzir esse bug, tente pressionar dois controladores de exibição ao mesmo tempo. Ou empurrando e aparecendo ao mesmo tempo. Exemplo:
Eu criei uma categoria que intercepta essas chamadas e as torna seguras, certificando-se de que nenhum outro push esteja acontecendo enquanto um estiver em andamento. Basta copiar o código no seu projeto e, devido ao método swizzling, você estará pronto.
fonte
popToRootViewController
oupopToViewController:
quando já estiver no controlador de exibição raiz ou no viewController, eledidShowViewController
não será chamado e ficará presoviewTransitionInProgress
.self.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)viewController; [self.interactivePopGestureRecognizer setEnabled:YES];
Quando o reconhecedor foi desativado? E como você sabe o que o delegado deve ser? Com essas falas, para mim, ele quebra o gesto pop depois de aparecer uma vez.Acabei de experimentar esse problema também. Deixe-me mostrar meu código:
O erro surge devido a esta linha:
Você não pode adicionar auto à subview. Alterei a linha de código para:
O erro foi resolvido e eu pude ver as duas visualizações. Só pensei que isso ajudaria quem quisesse ver um exemplo.
fonte
Pesquise seu código por "addSubview".
Em um dos lugares que você chamou esse método, você tentou adicionar uma exibição à sua própria matriz de sub-exibições usando esse método.
Por exemplo:
Ou:
fonte
[View2.view addSubview:View2.view]
adicionando self como subview.Eu acho que empurrar / abrir os controladores de exibição com animação a qualquer momento deve estar perfeitamente bem e o SDK deve lidar graciosamente com a fila de chamadas para nós.
Portanto, isso não ocorre e todas as soluções tentam ignorar os empurrões subsequentes, o que pode ser considerado um bug, já que a pilha de navegação final não é o que o código pretendia.
Eu implementei uma fila de chamadas push:
Ele não lida com filas mistas de push e pop, mas é um bom começo para corrigir a maioria de nossas falhas.
Gist: https://gist.github.com/rivera-ernesto/0bc628be1e24ff5704ae
fonte
Desculpe por estar atrasado para a festa. Recentemente, tive um problema em que minha barra de navegação entra em estado corrompido por pressionar mais de um controlador de exibição ao mesmo tempo. Isso acontece porque o outro controlador de exibição é pressionado enquanto o primeiro controlador de exibição ainda está animado. Tomando dica da resposta não-elástica, vim com minha solução simples que funciona no meu caso. Você só precisa subclassificar
UINavigationController
e substituir o método pushViewController e verificar se a animação anterior do controlador de exibição ainda está concluída. Você pode ouvir a conclusão da animação transformando sua classe em um delegadoUINavigationControllerDelegate
e definindo-o comoself
.Fiz upload de uma essência aqui para simplificar as coisas.
Apenas certifique-se de definir esta nova classe como o NavigationController no seu storyboard.
fonte
Com base na ótima dica do @RobP, criei a subclasse UINavigationController para evitar esses problemas. Ele lida com push e / ou popping e você pode executar com segurança:
Se o sinalizador 'acceptConflictingCommands' for verdadeiro (por padrão), o usuário verá o envio animado de vc1, vc2, vc3 e, em seguida, o envio animado de vc3. Se 'acceptConflictingCommands' for falso, todas as solicitações push / pop serão descartadas até que vc1 seja totalmente pressionado - portanto, outras 3 chamadas serão descartadas.
fonte
animated:true
sinalizador?A solução da Nonamelive é incrível. Mas, se você não quiser usar a API privada, poderá apenas obter o
UINavigationControllerDelegate
método ou alterar a animaçãoYES
paraNO
. Aqui está um exemplo de código, você pode herdar. Espero que seja útil :)https://github.com/antrix1989/ANNavigationController
fonte
Eu tinha pesquisado muito esse problema, talvez pressionando dois ou mais VC ao mesmo tempo, o que causa o problema de animação por push, você pode se referir a isso: Não é possível adicionar auto como subvisão 崩溃 解决 办法
apenas verifique se há um VC no progresso da transição ao mesmo tempo - boa sorte.
fonte
Às vezes, você tentou erroneamente adicionar uma exibição à sua própria exibição.
altere isso para sua sub-visualização.
fonte
Eu também encontrei esse problema. Quando fiz a análise de log do Firebase, descobri que esse problema ocorre apenas quando o aplicativo é iniciado a frio. Então, eu escrevi uma demonstração que pode reproduzir essa falha.
.
Também descobri que, quando o controlador de exibição raiz da janela é exibido, executar vários toques não causa o mesmo problema novamente. (Você pode comentar testColdStartUp (rootNav) em AppDelegate.swift e descomentar o comentário testColdStartUp () em ViewController.swift)
ps: analisei a cena desse acidente no meu aplicativo. Quando o usuário clica na notificação push para iniciar o aplicativo a frio, ele ainda está na página Iniciar e clica em outro push para pular. No momento, o aplicativo pode aparecer o Crash. Meu atual A solução é armazenar em cache o push ou o link universal a frio para abrir a página de salto do aplicativo, aguardar a exibição do controlador rootview e atrasar a execução.
fonte
tente sua navegação usando o método delay, para concluir a última animação de navegação,
[self performSelector:<#(SEL)#> withObject:<#(id)#> afterDelay:<#(NSTimeInterval)#>]
fonte
Uma visualização não pode ser adicionada como uma subvisão nela mesma.
As visualizações mantêm uma hierarquia pai-filho; portanto, se você incluir uma visualização como uma subvisão em si, será por exceção.
se uma classe for UIViewController, para obter sua visualização, use self.view.
se uma classe é UIView Class, para obter sua visão, você usa-se.
fonte
você não pode adicionar self como subview, se for uma classe UiViewController. você pode adicionar self como subview, se for uma classe UiView.
fonte
Se você deseja adicionar uma Subview a uma View, pode fazê-lo assim;
fonte