dismissModalViewControllerAnimated deprecated

Acabei de atualizar para o XCode 4.5 para atualizar meu aplicativo iOS para ser executado na tela de 4 polegadas do iPhone 5, mas estou recebendo um erro de criaçãodismissModalViewControllerAnimated:' is deprecated na linha:

[self dismissModalViewControllerAnimated:NO];

Eu tentei atualizar para a sobrecarga recomendada com um manipulador de conclusão (mas definido como NULL) assim:

[self dismissModalViewControllerAnimated:NO completion:NULL];

Mas então esta linha lança dois erros:

warning: 'TabBarController' may not respond to '-presentModalViewController:animated:completion:'
Instance method '-presentModalViewController:animated:completion:' not found (return type defaults to 'id')

Obrigado!

questionAnswers(6)

Agora, no iOS 6 e acima, você pode usar:

[[Picker presentingViewController] dismissViewControllerAnimated:YES completion:nil];

Ao invés de:

[[Picker parentViewControl] dismissModalViewControllerAnimated:YES];

... E você pode usar:

[self presentViewController:picker animated:YES completion:nil];

Ao invés de

[self presentModalViewController:picker animated:YES];    
QuestionSolution

O novo método é:

[self dismissViewControllerAnimated:NO completion:nil];

A palavramodal foi removido; Como foi para a chamada da API de apresentação:

[self presentViewController:vc animated:NO completion:nil];

As razões foram discutidas no2012 WWDC Session 236 - A Evolução dos Controladores de Visualização no iOS Vídeo. Essencialmente, os controladores de visualização apresentados por essa API não são mais sempre modais e, como estavam adicionando um manipulador de conclusão, era um bom momento para renomeá-lo.

Em resposta ao comentário de Marc:

Qual é a melhor maneira de suportar todos os dispositivos 4.3 e acima? O novo método não funciona no iOS4, mas o método antigo está obsoleto no iOS6.

Eu percebo que esta é uma questão quase que separada, mas acho que vale a pena mencionar, já que nem todo mundo tem dinheiro para atualizar todos os seus dispositivos a cada três anos, então muitos de nós temos alguns dispositivos antigos (pré 5.0). Ainda assim, por mais que me doa dizer isso, você precisa considerar se vale a pena segmentar abaixo de 5.0. Existem muitas APIs novas e interessantes que não estão disponíveis abaixo de 5.0. E a Apple está continuamente tornando mais difícil direcioná-los; O suporte armv6 é descartado do Xcode 4.5, por exemplo.

Para segmentar abaixo de 5.0 (contanto que o bloco de conclusão seja nulo), basta usar o práticorespondsToSelector: método.

if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){
    [self presentViewController:test animated:YES completion:nil];
} else {
    [self presentModalViewController:test animated:YES];
}

Em resposta a outro comentário de Marc:

Isso poderia ser um monte de instruções If em meu aplicativo! ... Eu estava pensando em criar uma categoria que encapsulasse esse código, criando uma categoria no UIViewControler e me rejeitando?

e um da Full Decent:

... existe uma maneira de causar manualmente que não apresente um aviso de compilador?

Em primeiro lugar, não, criar uma categoria emUIViewController por si só não terá seu aplicativo rejeitado; a menos que esse método de categoria chame APIs privadas ou algo semelhante.

Um método de categoria é um lugar extremamente bom para esse código. Além disso, como haveria apenas uma chamada para a API preterida, haveria apenas um aviso do compilador.

Para endereçar o comentário da Full Decent (pergunta), sim você pode suprimir os avisos do compilador manualmente.Aqui está um link para uma resposta sobre SO nesse mesmo assunto. Um método de categoria também é um ótimo lugar para suprimir um aviso de compilador, já que você está apenas suprimindo o aviso em um só lugar. Você certamente não quer sair por aí silenciando o compilador, quer queira quer não.

Se eu fosse escrever um método de categoria simples para isso, poderia ser algo assim:

@implementation UIViewController (NJ_ModalPresentation)
-(void)nj_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion{
    NSAssert(completion == nil, @"You called %@ with a non-nil completion. Don't do that!",NSStringFromSelector(_cmd));
    if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){
        [self presentViewController:viewControllerToPresent animated:flag completion:completion];
    } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [self presentModalViewController:viewControllerToPresent animated:flag];
#pragma clang diagnostic pop
    }
}
@end
 NJones26 de set de 2012 01:14
@Marc eu adicionei a minha resposta para resolver sua preocupação.
 Marc24 de set de 2012 18:30
Qual é a melhor maneira de suportar todos os dispositivos 4.3 e acima? O novo método não funciona no iOS4, mas o método antigo está obsoleto no iOS6. Rock e um lugar difícil?
 NJones22 de mai de 2013 16:08
@FullDecent Sim, você pode. Eu editei minha resposta com algumas informações sobre isso.
 Jason McCreary04 de set de 2013 17:41
O receptor deve mudar dependendo de onde isso é chamado? Isto é, você pode usarpresentingViewController?
 NJones22 de set de 2013 17:03
@JasonMcCreary Geralmente você pode simplesmente usar[self dismiss… e encaminhará automaticamente para opresentingViewController. A exceção é se você tiver vários controladores de exibição apresentados (na moda anteriormente conhecida como modal); se este for o caso, você direciona odismiss… Chame ao controlador de visualização cuja visão você deseja manter após a demissão, todas as visualizações acima serão descartadas de uma só vez.
 William Entriken21 de mai de 2013 00:11
Para o códigoif ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){ [self presentViewController:test animated:YES completion:nil]; } else { [self presentModalViewController:test animated:YES]; } Existe uma maneira de manualmente causar que não apresentar um aviso de compilador?
 Marc26 de set de 2012 10:44
Obrigado. Isso pode ser um monte de instruções If no meu aplicativo! Eu acho que a mesma abordagem poderia funcionar ao usar a propriedade 'modalViewController'. Eu estava pensando em criar uma categoria que encapsulasse esse código, criar uma categoria no UIViewControler e me rejeitar?

[self dismissModalViewControllerAnimated:NO]; foi reprovado.

Usar[self dismissViewControllerAnimated:NO completion:nil]; em vez de.

Usar

[self dismissViewControllerAnimated:NO completion:nil];

O aviso ainda está lá. Para se livrar disso eu coloquei em um seletor como este:

if ([self respondsToSelector:@selector(dismissModalViewControllerAnimated:)]) {
    [self performSelector:@selector(dismissModalViewControllerAnimated:) withObject:[NSNumber numberWithBool:YES]];
} else {
    [self dismissViewControllerAnimated:YES completion:nil];
}

Beneficia pessoas com TOC como eu;)

 Jsdodgers28 de jul de 2013 00:25
Você deve mudar a instrução if porque acredito que um método obsoleto não causarárespondsToSelector para retornar falso. Assim, o novodismissViewControllerAnimated: nunca será chamado até uma atualização futura onde eles possam possivelmente removerdismissModalViewControllerAnimated: completamente.

Aqui está a versão presentViewController correspondente que usei se ajudar outros novatos como eu:

if ([self respondsToSelector:@selector(presentModalViewController:animated:)]) {
    [self performSelector:@selector(presentModalViewController:animated:) withObject:testView afterDelay:0];
} else {
    [self presentViewController:configView animated:YES completion:nil];
}
[testView.testFrame setImage:info]; //this doesn't work for performSelector
[testView.testText setHidden:YES];

Eu tinha usado um ViewController 'genericamente' e consegui fazer com que a View modal aparecesse de maneira diferente, dependendo do que era chamado para fazer (usando setHidden e setImage). e as coisas estavam funcionando bem antes, mas performSelector ignora o 'set', então no final parece ser uma má solução se você tentar ser eficiente como eu tentei ser ...

yourAnswerToTheQuestion