despedirModalViewControllerAnimated obsoleto

103

Acabo de actualizar a XCode 4.5 para actualizar mi aplicación iOS para que se ejecute en la pantalla de 4 pulgadas del iPhone 5, pero recibo un error de compilación que dice dismissModalViewControllerAnimated:' is deprecateden la línea:

[self dismissModalViewControllerAnimated:NO];

Intenté actualizar a la sobrecarga recomendada con un controlador de finalización (pero configurado en NULL) como este:

[self dismissModalViewControllerAnimated:NO completion:NULL];

Pero luego esta línea arroja dos errores:

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

¡Gracias!

Mick Byrne
fuente

Respuestas:

307

El nuevo método es:

[self dismissViewControllerAnimated:NO completion:nil];

Se ha eliminado la palabra modal ; Como ha sido para la presentación de la llamada API:

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

Las razones se discutieron en la sesión 236 de la WWDC de 2012: La evolución de los controladores de vista en video de iOS . Esencialmente, los controladores de vista presentados por esta API ya no son siempre modales y, dado que estaban agregando un controlador de finalización, era un buen momento para cambiarle el nombre.

En respuesta al comentario de Marc:

¿Cuál es la mejor manera de admitir todos los dispositivos 4.3 y superiores? El nuevo método no funciona en iOS4, pero el método anterior está obsoleto en iOS6.

Me doy cuenta de que esta es casi una pregunta separada, pero creo que vale la pena mencionarla, ya que no todos tienen el dinero para actualizar todos sus dispositivos cada 3 años, por lo que muchos de nosotros tenemos algunos dispositivos más antiguos (anteriores a 5.0). Aún así, por mucho que me duela decirlo, debes considerar si vale la pena apuntar por debajo de 5.0. Hay muchas API nuevas y geniales que no están disponibles por debajo de 5.0. Y Apple continuamente hace que sea más difícil apuntar a ellos; La compatibilidad con armv6 se elimina de Xcode 4.5, por ejemplo.

Para apuntar por debajo de 5.0 (siempre que el bloque de finalización sea nulo) simplemente use el respondsToSelectormétodo handy :.

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

En respuesta a otro comentario de Marc:

¡Eso podría ser una gran cantidad de declaraciones If en mi aplicación! ... Estaba pensando en crear una categoría que encapsulara este código, ¿la creación de una categoría en UIViewControler me rechazaría?

y uno de Full Decent:

... ¿hay alguna manera de hacer que eso no presente manualmente una advertencia del compilador?

En primer lugar, no, crear una categoría en UIViewControllersí mismo no hará que su aplicación sea rechazada; a menos que ese método de categoría se llame API privadas o algo similar.

Un método de categoría es un lugar excelente para tal código. Además, dado que solo habría una llamada a la API obsoleta, solo habría una advertencia del compilador.

Para abordar el comentario (pregunta) de Full Decent, sí, puede suprimir las advertencias del compilador manualmente. Aquí hay un enlace a una respuesta sobre SO sobre ese mismo tema . Un método de categoría también es un gran lugar para suprimir una advertencia del compilador, ya que solo está suprimiendo la advertencia en un lugar. Ciertamente, no querrá andar silenciando el compilador.

Si tuviera que escribir un método de categoría simple para esto, podría ser algo como esto:

@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
fuente
2
¿Cuál es la mejor manera de admitir todos los dispositivos 4.3 y superiores? El nuevo método no funciona en iOS4, pero el método anterior está obsoleto en iOS6. ¿Sitio de rock duro?
Marc
@Marc agregué a mi respuesta para abordar su preocupación.
NJones
Gracias. ¡Eso podría ser un montón de declaraciones If en mi aplicación! Supongo que el mismo enfoque podría funcionar cuando se usa la propiedad 'modalViewController'. Estaba pensando en crear una categoría que encapsulara este código, ¿la creación de una categoría en UIViewControler me rechazaría?
Marc
Para el código, if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){ [self presentViewController:test animated:YES completion:nil]; } else { [self presentModalViewController:test animated:YES]; }¿hay alguna manera de hacer que manualmente no presente una advertencia del compilador?
William Entriken
@FullDecent Sí, puedes. Edité mi respuesta con algo de información al respecto.
NJones
6

Ahora en iOS 6 y superior, puede usar:

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

En vez de:

[[Picker parentViewControl] dismissModalViewControllerAnimated:YES];

... Y puedes usar:

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

En vez de

[self presentModalViewController:picker animated:YES];    
Dipang
fuente
4

[self dismissModalViewControllerAnimated:NO]; ha quedado obsoleto.

Úselo en su [self dismissViewControllerAnimated:NO completion:nil];lugar.

Jayprakash Dubey
fuente
4

Utilizar

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

La advertencia sigue ahí. Para deshacerme de él, lo puse en un selector como este:

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

Beneficia a personas con TOC como yo;)

kjoelbro
fuente
Debe cambiar la declaración if porque creo que un método obsoleto no hará respondsToSelectorque devuelva falso. Por lo tanto, el nuevo dismissViewControllerAnimated:no se llamará nunca hasta una actualización futura donde posiblemente se eliminen por dismissModalViewControllerAnimated:completo.
Jsdodgers
0

Aquí está la versión de presentViewController correspondiente que usé si ayuda a otros novatos como yo:

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

Había usado un ViewController 'genéricamente' y pude hacer que la Vista modal apareciera de manera diferente dependiendo de lo que se le llamó (usando setHidden y setImage). y las cosas funcionaban bien antes, pero performSelector ignora las cosas de 'set', por lo que al final parece ser una mala solución si intentas ser eficiente como yo traté de ser ...

Walter
fuente