Aviso: -Apresentação de controladores de exibição em controladores de exibição desconectados é desencorajada

180

No meu aplicativo, estou usando um controlador de navegação. Mais tarde, de alguma forma, estou usando presentViewControllerpara mostrar uma imagem ampliada. Também não estou usando um Storyboard ou uma ponta.

Estou recebendo esse erro apenas no iOS 7. Funciona bem no iOS 6 e versões anteriores:

A apresentação de controladores de vista em controladores de vista desanexada é desencorajada

Gagan Joshi
fonte
Eu ainda não descobri. Mas no meu aplicativo não estou atribuindo nenhum viewcontroller ao window.rootviewcontroller. Estou adicionando vista à janela. Pode ser que seja a razão para mim. mas não tenho certeza ...
Gagan Joshi
@GaganJoshi O motivo que você mencionou acima pode não ser a causa. Até eu estou enfrentando o mesmo problema. E em nosso projeto, estou atribuindo um controlador de exibição ao window.rootviewcontroller.
Rajesh
1
Acho que os outros comentários relacionam isso corretamente com algo sobre o rootViewController e a conexão da janela. Ainda não descobri isso, mas consegui solucionar o problema apresentando o controlador diretamente no rootViewController, em vez de no controlador de navegação ou em um de seus filhos.
Rich Waters
Azaxis conseguiu: stackoverflow.com/a/31877722/5306470
Daniel Springer

Respostas:

207

Para evitar receber o aviso em uma navegação por push, você pode usar diretamente:

[self.view.window.rootViewController presentViewController:viewController animated:YES completion:nil];

E então, no seu controlador de exibição modal, quando tudo estiver concluído, você pode simplesmente chamar:

[self dismissViewControllerAnimated:YES completion:nil];

cdescours
fonte
Estou apresentando o seletor de imagens com este código de linha "[self.view.window.rootViewController presentViewController: viewController animado: conclusão do SIM: nil];" Mas não é possível descartar a exibição do apontador com esta linha "[auto-dispensarViewControllerAnimated: YES conclusão: nil];" Qualquer opção alternativa para dismisscontroller
kb920
@keyurbhalodiya Você precisa chamar o método unlockViewController no modalView para fazê-lo funcionar. Portanto, se você exibiu uma visualização denominada viewB de uma viewA com [viewA.window.rootViewController presentViewController: viewB], no viewB, é necessário adicionar um botão, por exemplo, associado a uma ação personalizada chamada [selfmissViewViewControllerAnimated]. Está mais claro?
Cdescours
11
Não apresentando viewcontroller no iOS 8.
Rajesh Maurya
1
para iOS 8: [self.view.window.rootViewController.navigationController
Fede Cugliandolo
31
usando self.navigationControllerfez isso por mim.
precisa
62

O motivo desse aviso é que eu estava apresentando um controlador de exibição em uma exibição pequena que não é de tamanho completo. Dada a seguir é a imagem do meu projeto. onde clique em quatro opção acima. O usuário navega para a visão diferente do controlador de visualização infantil (funciona como tabViewcontroller). Mas o childviewcontroller contém uma exibição de tamanho pequeno. Portanto, se apresentarmos uma visão do childviewcontroller, ele fornece esse aviso.

visualização de detalhes mestre

E para evitar isso, você pode apresentar uma visão sobre o pai do controlador de visualização infantil

  [self.parentViewController presentViewController:viewController animated:YES completion:nil];
Gagan Joshi
fonte
1
[self.view.window.rootViewController.navigationController pushViewController: YOUR_VIEW_CONTROLER animado: SIM];
Fede Cugliandolo
1
"estava apresentando um controlador de exibição em uma exibição pequena que não é de tamanho completo." ... EXATAMENTE. Bom trabalho.
Gordo
61

Aguarde viewDidAppear():

Este erro também pode surgir se você estiver tentando apresentar o controlador de vista antes que a vista realmente apareça, por exemplo, apresentando vista no viewWillAppear()anterior. Tente apresentar outra visão depois viewDidAppear()ou dentro dela.

Azaxis
fonte
9
Em outras palavras, não apresente nenhum controlador de exibição viewDidLoad(), pessoal! Eu cometi este erro tantas vezes ...
T branco
Graças isso ajudou. Eu tinha o código no viewDidLoad onde ele tentou exibir uma caixa de diálogo no final.
ArdenDev 10/07
Estou recebendo esse erro ao executar testes de unidade / integração em que não testo com animações.
mixtly87
21

No meu caso, eu tenho uma sampleViewControllervisualização adicionada como uma subvisão e, em seguida, tenta apresentar um popover a partir da visualização sampleViewController(aqui, em selfvez de uma UIViewControllerinstância):

[self.view addSubview:sampleViewController.view];

O caminho certo deve estar abaixo:

// make sure the vc has been added as a child view controller as well
[self addChildViewController:sampleViewController];
[self.view addSubview:sampleViewController.view];
[sampleViewController didMoveToParentViewController:self];

Btw, isso também funciona para o caso de apresentar uma popover de uma célula de tableview, você só precisa garantir que o controlador tableview também tenha sido adicionado como controlador de exibição filho.

Kjuly
fonte
Além disso, chame didMoveToParentViewController. Pleaes confira Adicionar e Remover ChildViewController: gist.github.com/tomohisa/2897676
Jakehao
@jianzong Lembro que não há necessidade de fazer o último passo. De qualquer forma, deixe-me adicioná-lo, thx pela sugestão. :)
Kjuly
Sim, funcionará sem o último passo. Acho que o objetivo é informar o parentViewController para que ele chame alguns métodos para fazer alguma coisa. :)
Jakehao
2
ele trabalha para mim, im usando os controladores de uma exibição em outro controlador - (Container visualizar programaticamente), eu não adicionar [self addChildViewController:sampleViewController];, agora eu adicionado este, obrigado
anjnkmr
16

Eu acho que o problema é que você não tem uma hierarquia de controlador de exibição adequada. Defina o rootviewcontroller do aplicativo e mostre novas visualizações pressionando ou apresentando novos controladores de visualização neles. Permita que cada controlador de visualização gerencie suas visualizações. Somente controladores de exibição de contêiner, como o tabbarviewcontroller, devem adicionar outras visualizações de controladores de exibição às suas próprias visualizações. Leia o guia de programação dos controladores de exibição para saber mais sobre como usar os controladores de exibição corretamente. https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/

Daniel Ytterbrink
fonte
14

Swift 3

Para quem se deparar com isso, aqui está a resposta rápida.

self.parent?.present(viewController, animated: true, completion: nil)
Jeremie
fonte
9

Eu tenho quase o mesmo problema. O motivo foi que tentei apresentar "alguns" controladores em outro e após a animação ser concluída, eu estava configurando o controlador apresentado como root. Após esta operação, todos os outros controladores apresentados me trazem o aviso: "A apresentação de controladores de exibição em controladores de exibição desanimada é desencorajada ". E eu resolvo esse aviso apenas configurando "alguns" controladores como root sem nenhuma apresentação no início.

Removido:

[[self rootController] presentViewController:controller animated:YES completion:^{

       [self window].rootViewController = controller;

       [[self window] makeKeyAndVisible];}];

Faça como root sem nenhuma apresentação:

 [[self window] setRootViewController:controller];
averem
fonte
1
Este foi exatamente o meu problema. Estava tentando apresentá-lo com um UIModalTransitionStyleCrossDissolve e, em seguida, torná-lo rootViewController. Depois disso, todas as outras apresentações estavam falhando com a mensagem de aviso fornecida. Apenas configurá-lo como rootViewcontroller sem animação fez o truque. Obrigado!
Bernardo Oliveira
7

Uma das soluções para isso é se você tem um childviewcontroller Então você simplesmente apresenta oviewview no seu pai por

[self.parentViewController presentViewController:viewController animated:YES completion:nil];

E para dispensar, use o mesmo controlador de dispensviewview.

[self dismissViewControllerAnimated:YES completion:nil];

Esta é a solução perfeita funciona para mim.

Gagan Joshi
fonte
7

Use [self.navigationController presentViewController:xxx animated:YES completion:nil]no iOS 8.

Tao Fang
fonte
5

Experimente este código

UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:<your ViewController object>];

[self.view.window.rootViewController presentViewController:navigationController animated:YES completion:nil];
Vlad
fonte
4

Tente apresentar TabBarControllerse é um TabBarControlleraplicativo baseado.

[self.tabBarController presentViewController:viewController animated:YES completion:nil];

A razão pode ser selfsua filha TabBarControllere você está tentando apresentar de a ChildViewController.

Warif Akhand Rishi
fonte
4

Sim, também recebi a mesma mensagem de aviso ao exibir um controlador de alerta que estava em outra exibição. Mais tarde, evitei isso apresentando o controlador de alerta do controlador de exibição pai, como abaixo:

[self.parentViewController presentViewController:alertController animated:YES completion:nil];
Sivasagar Palakurthy
fonte
3

você precisa adicionar o controlador de exibição que apresentará o novo controlador como filho do controlador de exibição pai.

Digamos que você tenha o seu MainViewController, adicione um novo controlador chamado controllerA e, em seguida, deseje apresentar um novo controlador chamado controllerB do controllerA

você tem que escrever algo como isto:

[self addChildViewController:controllerA]; //self is yourMainViewController
[self.view addsubView:controllerA.view]; 

e no controllerA você pode apresentar o novo controller sem avisos

[self presentViewController:controllerB animated:YES completion:nil]; //self is controllerA
Chuy47
fonte
3

No Swift 4.1 e no Xcode 9.4.1

A solução é

DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})

Se escrever assim, estou recebendo o mesmo erro

let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
    })
alert.addAction(defaultAction)

present(alert, animated: true, completion: nil) 

Estou recebendo o mesmo erro

Presenting view controllers on detached view controllers is discouraged <MyAppName.ViewController: 0x7fa95560Z070>.

A solução completa é

let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
     })
alert.addAction(defaultAction)
//Made Changes here    
DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})
iOS
fonte
Executá-lo através do DispatchQueue como este funcionou para mim. Estou executando um performSegue em um controlador de exibição modal, chamado a partir do viewDidLoad no meu primeiro controlador de exibição (uma primeira tela de introdução para orientar novos usuários). Estava carregando bem, mas gerando o aviso. O agrupamento da chamada performSegue na chamada assíncrona DispatchQueue elimina o aviso. Obrigado!
Grant Neufeld
1

Certifique-se de ter um controlador de visualização raiz para começar. Você pode configurá-lo didFinishLaunchingWithOptions.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    [window setRootViewController:viewController];
}
samwize
fonte
1

Muitas razões para este aviso. O meu é porque eu tenho um segue conectado de um ViewController a outro que será apresentado de forma modal. Mas, o ViewController de que estou apresentando está sendo gerado dinamicamente por um PageViewController. É por isso que ele é desanexado no Storyboard. Meu aplicativo não falhará por causa disso; mas gostaria de silenciar o aviso.

Lee Probert
fonte
1

Cheguei a esse segmento em que tenho uma barra de navegação personalizada e estava chamando um AlertViewController por meio dele.

Eu tive que adicioná-lo quando criança ao meu controlador de exibição principal. Então eu poderia ligar para apresentá-lo sem nenhum aviso.

Você deve adicionar seu Zoomed Image View Controllerfilho do ViewController principal.

(por exemplo)

[self addChildViewController:ZoomedImageViewController];

Em seguida, você poderá ligar para o seu ZoomedImageViewController

[self presentViewController:ZoomedImageViewController];
Abbas Naveed
fonte
1

Muitas respostas estão certas.

  • Verifique se o seu PresentationViewController tem parentViewController ou não.
  • Se não, adicione-o a algum lugar em que ele deve ser adicionado
  • caso contrário, verifique se parentViewController tem parentViewController recursivamente até que cada viewController tenha pai

Esse problema aconteceu comigo quando meu colega de trabalho adicionou um AViewController ao BViewController. De alguma forma, ele acabou de adicionar a visão do AViewController à visão do BViewController.

Corrigido por add bViewController.addChild (aViewController)

Jerome Li
fonte
1
Obrigado! adicionar addChild no meu bloco de conclusão Hero.shared.transition resolveu completamente o meu problema.
landnbloc 16/03
0

Depende se você deseja mostrar seu alerta ou algo semelhante em qualquer lugar do tipo UIViewController.

Você pode usar este exemplo de código:

UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Alert" message:@"Example" preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:nil];

[alert addAction:cancelAction];


[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:alert animated:true completion:nil];
Fabio
fonte
Com seu código, ele não funciona e fornece esse logAttempt to present <UIAlertController: 0x7fc01a1eb600> on <ViewController: 0x7fc019821e00> whose view is not in the window hierarchy!
Naveed Abbas