Dispensando um controlador de visualização apresentado

116

Eu tenho uma questão teórica. Agora estou lendo o guia ViewController da Apple .

Eles escreveram:

Quando chega a hora de dispensar um controlador de visualização apresentado, a abordagem preferida é permitir que o controlador de visualização em apresentação o descarte. Em outras palavras, sempre que possível, o mesmo controlador de visualização que apresentou o controlador de visualização também deve assumir a responsabilidade por descartá-lo. Embora existam várias técnicas para notificar o controlador de visualização de apresentação que seu controlador de visualização apresentado deve ser dispensado, a técnica preferida é a delegação.

Mas eu não posso explicar, porque eu tenho que criar um protocolo no VC apresentado e adicionar a variável delegada, criar o método delegado na apresentação do VC para dispensar o VC apresentado, em vez de uma chamada simples no método do controlador de visualização apresentado

[self dismissViewControllerAnimated:NO completion:nil]?

Por que a primeira escolha é melhor? Por que a Apple o recomenda?

Nikitahils
fonte

Respostas:

122

Acho que a Apple está se protegendo um pouco aqui por causa de um pedaço de API potencialmente confuso.

  [self dismissViewControllerAnimated:NO completion:nil]

Na verdade, é meio violino. Embora você possa - legitimamente - chamar isso no controlador de exibição apresentado, tudo o que ele faz é encaminhar a mensagem para o controlador de exibição de apresentação. Se você quiser fazer qualquer coisa além de simplesmente dispensar o VC, você precisará saber disso e tratá-lo da mesma forma que um método de delegação - já que isso é basicamente o que é, um método interno um tanto inflexível método delegado.

Talvez eles tenham se deparado com um monte de códigos ruins feitos por pessoas que não entendem realmente como isso é feito, daí sua cautela.

Mas, claro, se tudo o que você precisa fazer é descartar a coisa, vá em frente.

Minha própria abordagem é um meio-termo, pelo menos me lembra o que está acontecendo:

  [[self presentingViewController] dismissViewControllerAnimated:NO completion:nil]

[Rápido]

  self.presentingViewController?.dismiss(animated: false, completion:nil)
fundição
fonte
26
Deve-se notar que usar presentingViewControlleré quase inútil, pois se refere ao UINavigationControllerif selfestá embutido em um. Nesse caso, você não conseguirá obter o presentingViewController. No entanto, [self dismissViewControllerAnimated:completion]ainda funciona nesse caso. Minha sugestão seria continuar a usar isso até que a Apple conserte.
memmons
4
Adoro que esta resposta ainda seja totalmente relevante 3 anos depois.
user1021430
1
Outra coisa a considerar é que um controlador de visualização não sabe como foi exibido. Ele pode ter sido apresentado, colocado em um controlador de navegação, parte de um controlador de barra de guias, etc. Usar o delegado permite que o controlador de exibição "apresentando" "rejeite" o controlador de exibição usando o inverso de qualquer método usado para apresentá-lo.
David Smith
51

Atualizado para Swift 3

Eu vim aqui apenas querendo descartar o View Controller atual (apresentado). Estou respondendo a qualquer pessoa que venha aqui com o mesmo propósito.

Controlador de navegação

Se você estiver usando um controlador de navegação, é muito fácil.

Volte para o controlador de visualização anterior:

// Swift
self.navigationController?.popViewController(animated: true)

// Objective-C
[self.navigationController popViewControllerAnimated:YES];

Volte para o controlador de visualização raiz:

// Swift
self.navigationController?.popToRootViewController(animated: true)

// Objective-C
[self.navigationController popToRootViewControllerAnimated:YES];

(Graças a esta resposta para o Objective-C.)

Modal View Controller

Quando um View Controller é apresentado modalmente, você pode dispensá-lo (no segundo view controller) chamando

// Swift
self.dismiss(animated: true, completion: nil)

// Objective-C
[self dismissViewControllerAnimated:YES completion:nil];

A documentação diz:

O controlador de visualização de apresentação é responsável por descartar o controlador de visualização que ele apresentou. Se você chamar este método no próprio controlador de visualização apresentado, o UIKit pede ao controlador de visualização de apresentação para lidar com a dispensa.

Portanto, funciona para o controlador de visualização apresentado chamá-lo sobre si mesmo. Aqui está um exemplo completo.

Delegados

A pergunta do OP era sobre a complexidade de usar delegados para rejeitar uma visão.

Até este ponto, não precisei usar delegados, já que geralmente tenho um controlador de navegação ou controladores de visualização modal, mas se eu precisar usar o padrão de delegado no futuro, adicionarei uma atualização.

Suragch
fonte
50

Isso é para reutilização do controlador de exibição.

Seu controlador de visualização não deve se importar se está sendo apresentado como modal, pressionado em um controlador de navegação ou qualquer outra coisa. Se o seu controlador de visualização dispensa a si mesmo, então você está assumindo que ele está sendo apresentado modalmente. Você não poderá empurrar esse controlador de visualização para um controlador de navegação.

Ao implementar um protocolo, você permite que o controlador de visualização pai decida como ele deve ser apresentado / enviado e descartado / descartado.

Michael Enriquez
fonte
7

tente isto:

[self dismissViewControllerAnimated:true completion:nil];
Oshitha Wimalasuriya
fonte
6

Na minha experiência, ele é útil quando você precisa dispensá-lo de qualquer ViewController que desejar e realizar tarefas diferentes para cada viewcontroller que o dispensa. Qualquer viewController que adote o protocolo pode dispensar a visualização de sua própria maneira. (ipad vs iphone, ou passar dados diferentes ao dispensar de visualizações diferentes, chamar métodos diferentes ao dispensar, etc.)

Editar:

Portanto, para esclarecer, se tudo o que você quer fazer é descartar a visualização, não vejo necessidade de configurar o protocolo de delegação. Se você precisar fazer coisas diferentes depois de dispensá-lo de diferentes controladores de visualização de apresentação, seria a melhor maneira de usar o delegado.

jhilgert00
fonte
mas se eu não precisar "passar dados diferentes ao dispensar de visualizações diferentes, chamar métodos diferentes ao dispensar, etc.", posso fazer uma pequena chamada no método do controlador de visualização apresentado - [self dispensViewControllerAnimated: SEM conclusão: nulo]?
nikitahils
Deixar o apresentador dispensar a visão apresentada torna óbvio que o apresentador está de fato pronto e lidando com o retorno ao primeiro plano: a sequência de execução é fácil de seguir e a responsabilidade de qualquer atualização da IU é implicitamente clara.
Johan
2

Citação de View Controller Programming Guide , "Como View Controllers Apresentam Outros View Controllers".

Cada controlador de visão em uma cadeia de controladores de visão apresentados tem ponteiros para os outros objetos ao seu redor na cadeia. Em outras palavras, um controlador de exibição apresentado que apresenta outro controlador de exibição tem objetos válidos em ambas as propriedades PresentViewController e appearController. Você pode usar esses relacionamentos para rastrear a cadeia de controladores de visualização conforme necessário. Por exemplo, se o usuário cancelar a operação atual, você pode remover todos os objetos na cadeia dispensando o primeiro controlador de visualização apresentado. Dispensar um controlador de visualização descarta não apenas aquele controlador de visualização, mas também quaisquer controladores de visualização que ele apresentou.

Então, por um lado, ele proporciona um design bem balanceado, um bom desacoplamento, etc ... Mas, por outro lado, é muito prático, porque você pode voltar rapidamente a um determinado ponto na navegação.

Embora eu pessoalmente prefira usar segues de desenrolamento do que tentar retroceder na árvore de controladores de visualização de apresentação , que é o que a Apple fala neste capítulo, de onde vem a citação.

Svena
fonte
2

Um ponto é que essa é uma boa abordagem de codificação. Satisfaz muitos OOPprincípios, por exemplo, SRP, separação de interesses etc.

Portanto, o controlador de visualização que apresenta a visualização deve ser o único a descartá-la.

Por exemplo, uma imobiliária que dá uma casa com aluguel deve ser a autoridade para recuperá-la.

Abdurrahman Mubeen Ali
fonte
2

Swift 3.0 // Dispensar o View Controller em swift

self.navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
Pranit
fonte
1

Além da resposta de Michael Enriquez, posso pensar em outra razão pela qual esta pode ser uma boa maneira de se proteger de um estado indeterminado:

Digamos que ViewControllerA apresenta ViewControllerB modalmente. Mas, como você pode não ter escrito o código para ViewControllerA, você não está ciente do ciclo de vida de ViewControllerA. Ele pode dispensar 5 segundos (digamos) depois de apresentar seu controlador de visualização, ViewControllerB.

Nesse caso, se você estivesse simplesmente usando o dismissViewControllerViewControllerB para dispensar a si mesmo, acabaria em um estado indefinido - talvez não um travamento ou uma tela preta, mas um estado indefinido do seu ponto de vista.

Se, em vez disso, você estivesse usando o padrão de delegado, estaria ciente do estado de ViewControllerB e poderia programar para um caso como o que descrevi.

Mayur
fonte
1

Rápido

let rootViewController:UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!

        if (rootViewController.presentedViewController != nil) {
            rootViewController.dismiss(animated: true, completion: {
                //completion block.
            })
        }
Rishi Chaurasia
fonte
0

Se você estiver usando o modo modal view, ignore.

[self dismissViewControllerAnimated:NO completion:nil];
ErasmoOliveira
fonte
Como isso responde à pergunta: "Por que a primeira escolha é melhor? Por que a Apple a recomenda?"
jww
0

Isso é muita bobagem. A delegação é boa quando é necessária, mas se torna o código mais complexo - e torna - então deve haver uma razão para isso.

Tenho certeza de que a Apple tem seus motivos. Mas é mais claro e mais conciso simplesmente fazer com que o VC apresentado faça a dispensa, a menos que haja uma razão verdadeira para fazer o contrário e ninguém aqui até hoje apresentou uma que eu possa ver.

Os protocolos são excelentes quando são necessários, mas o design orientado a objetos nunca foi sobre ter módulos se comunicando desnecessariamente entre si.

Tom Love (co-desenvolvedor de Objective C) comentou certa vez que Objective C era "elegante", "pequeno", "nítido" e "bem definido" (em comparação com C ++). Fácil para ele dizer. Delegação é um recurso útil que parece ter sido usado em demasia "só porque", e embora eu goste de trabalhar com a linguagem, temo a ideia de me sentir compelido a usar sintaxe desnecessária para tornar as coisas mais complexas do que deveriam ser.

Expressão regular
fonte
Isso pode economizar um pouco de código inicialmente, mas sua abordagem causará muitas dores de cabeça conforme sua base de código crescer. Você deve entender os princípios orientados a objetos, como separação de interesses, caso contrário, você também pode codificar todo o seu aplicativo em um grande arquivo.
Werner Altewischer
-2

Você pode fechar a janela de supervisualização

self.view.superview?.window?.close()

MR.Code
fonte