IgnorarModalViewControllerAnimated obsoleto

103

Acabei de atualizar para o XCode 4.5 para atualizar meu aplicativo iOS para rodar na tela de 4 polegadas para o iPhone 5, mas estou recebendo um erro de compilação dizendo dismissModalViewControllerAnimated:' is deprecatedna linha:

[self dismissModalViewControllerAnimated:NO];

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

[self dismissModalViewControllerAnimated:NO completion:NULL];

Mas essa linha gera dois erros:

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

Obrigado!

Mick Byrne
fonte

Respostas:

307

O novo método é:

[self dismissViewControllerAnimated:NO completion:nil];

A palavra modal foi removida; Como foi para a apresentação da chamada de API:

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

Os motivos foram discutidos em 2012 WWDC Session 236 - The Evolution of View Controllers on iOS Video. Essencialmente, os controladores de visualização apresentados por esta 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 oferecer suporte a todos os dispositivos 4.3 e superior? O novo método não funciona no iOS4, mas o método antigo está obsoleto no iOS6.

Sei que essa é uma questão quase separada, mas acho que vale a pena mencionar, já que nem todo mundo tem dinheiro para atualizar todos os seus dispositivos a cada 3 anos, portanto, muitos de nós temos alguns dispositivos mais antigos (anteriores ao 5.0). Ainda assim, por mais que me dói dizer, você precisa considerar se vale a pena focar abaixo de 5,0. Existem muitas APIs novas e interessantes não disponíveis abaixo do 5.0. E a Apple está continuamente tornando mais difícil atingi-los; O suporte armv6 foi retirado do Xcode 4.5, por exemplo.

Para atingir abaixo de 5,0 (contanto que o bloco de conclusão seja nulo), use o respondsToSelectormétodo handy :.

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, criar uma categoria em UIViewControler me faria ser rejeitado?

e um da Full Decent:

... existe uma maneira de fazer com que isso não apresente um aviso do compilador manualmente?

Em primeiro lugar, não, criar uma categoria por UIViewControllersi só não fará com que seu aplicativo seja rejeitado; a menos que esse método de categoria seja chamado de 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 obsoleta, haveria apenas um aviso do compilador.

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

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
NJones
fonte
2
Qual é a melhor maneira de oferecer suporte a todos os dispositivos 4.3 e superior? O novo método não funciona no iOS4, mas o método antigo está obsoleto no iOS6. Rock e um lugar duro?
Marc
@Marc acrescentei à minha resposta para abordar sua preocupação.
NJones
Obrigado. Isso pode ser uma grande quantidade de instruções If em meu aplicativo! Eu acho que a mesma abordagem pode funcionar ao usar a propriedade 'modalViewController'. Eu estava pensando em criar uma categoria que encapsulasse esse código, criar uma categoria no UIViewControler me faria ser rejeitado?
Marc
Para o código, if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){ [self presentViewController:test animated:YES completion:nil]; } else { [self presentModalViewController:test animated:YES]; }existe uma maneira de fazer com que manualmente não apresente um aviso do compilador?
William Entriken
@FullDecent Sim, você pode. Editei minha resposta com algumas informações sobre isso.
NJones
6

Agora no iOS 6 e superior, 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];    
Dipang
fonte
4

[self dismissModalViewControllerAnimated:NO]; foi descontinuado.

Use em seu [self dismissViewControllerAnimated:NO completion:nil];lugar.

Jayprakash Dubey
fonte
4

Usar

[self dismissViewControllerAnimated:NO completion:nil];
Mak083
fonte
3

O aviso ainda está lá. Para me livrar dele, coloquei-o em um seletor assim:

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;)

Kjoelbro
fonte
Você deve mudar a instrução if porque acredito que um método obsoleto não causará o respondsToSelectorretorno falso. Assim, o novo dismissViewControllerAnimated:não será chamado até uma atualização futura, onde eles podem ser removidos dismissModalViewControllerAnimated:completamente.
Jsdodgers
0

Aqui está a versão correspondente do presentViewController que usei se ela 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 usei um ViewController 'genericamente' e consegui fazer com que a View modal aparecesse de forma diferente dependendo do que foi chamada para fazer (usando setHidden e setImage). e as coisas estavam funcionando bem antes, mas performSelector ignora as coisas de 'definir', então no final parece ser uma solução ruim se você tentar ser eficiente como eu tentei ser ...

Walter
fonte