dismissModalViewControllerAnimated przestarzałe

103

Właśnie zaktualizowałem do XCode 4.5, aby zaktualizować moją aplikację na iOS, aby działała na 4-calowym wyświetlaczu dla iPhone'a 5, ale pojawia się błąd kompilacji z komunikatem dismissModalViewControllerAnimated:' is deprecated:

[self dismissModalViewControllerAnimated:NO];

Próbowałem zaktualizować do zalecanego przeciążenia za pomocą programu obsługi zakończenia (ale ustawionego na NULL) w następujący sposób:

[self dismissModalViewControllerAnimated:NO completion:NULL];

Ale wtedy ta linia generuje dwa błędy:

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

Dzięki!

Mick Byrne
źródło

Odpowiedzi:

307

Nowa metoda to:

[self dismissViewControllerAnimated:NO completion:nil];

Słowo modalne zostało usunięte; Tak jak w przypadku prezentacji wywołania API:

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

Powody zostały omówione w 2012 WWDC Session 236 - The Evolution of View Controllers on iOS Video. Zasadniczo kontrolery widoku prezentowane przez ten interfejs API nie zawsze są modalne, a ponieważ dodawały procedurę obsługi zakończenia, była to dobra pora na zmianę nazwy.

W odpowiedzi na komentarz Marca:

Jaki jest najlepszy sposób na obsługę wszystkich urządzeń 4.3 i nowszych? Nowa metoda nie działa w iOS4, ale stara metoda jest przestarzała w iOS6.

Zdaję sobie sprawę, że jest to prawie osobne pytanie, ale myślę, że warto o tym wspomnieć, ponieważ nie każdy ma pieniądze na aktualizację wszystkich swoich urządzeń co 3 lata, więc wielu z nas ma starsze (starsze niż 5.0) urządzenia. Mimo to, choć boli mnie to powiedzieć, trzeba się zastanowić, czy warto kierować się poniżej 5,0. Istnieje wiele nowych i fajnych interfejsów API niedostępnych poniżej 5.0. Apple nieustannie utrudnia namierzenie ich; Wsparcie dla armv6 zostało na przykład usunięte z Xcode 4.5.

Aby celować poniżej 5,0 (o ile blok uzupełniania jest zerowy), po prostu użyj metody handy respondsToSelector:.

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

W odpowiedzi na inny komentarz Marca:

To może być całkiem sporo instrukcji If w mojej aplikacji! ... Myślałem o utworzeniu kategorii zawierającej ten kod, czy utworzenie kategorii na UIViewControler spowoduje odrzucenie mnie?

i jeden z Full Decent:

... czy istnieje sposób, aby ręcznie spowodować, że nie pojawi się ostrzeżenie kompilatora?

Po pierwsze, nie, utworzenie kategorii UIViewControllersamo w sobie nie spowoduje odrzucenia aplikacji; chyba że ta metoda kategorii nazywa się prywatnymi API lub czymś podobnym.

Metoda kategorii jest wyjątkowo dobrym miejscem na taki kod. Ponadto, ponieważ byłoby tylko jedno wywołanie przestarzałego interfejsu API, wystąpiłoby tylko jedno ostrzeżenie kompilatora.

Aby odpowiedzieć na komentarz (pytanie) Full Decent, tak, możesz ręcznie pominąć ostrzeżenia kompilatora. Oto link do odpowiedzi na SO na ten temat . Metoda kategorii jest również doskonałym miejscem do pomijania ostrzeżeń kompilatora, ponieważ pomijasz ostrzeżenie tylko w jednym miejscu. Na pewno nie chcesz chodzić dookoła wyciszania kompilatora chcąc nie chcąc.

Gdybym miał do tego napisać prostą metodę kategorii, mogłaby wyglądać następująco:

@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
źródło
2
Jaki jest najlepszy sposób na obsługę wszystkich urządzeń 4.3 i nowszych? Nowa metoda nie działa w iOS4, ale stara metoda jest przestarzała w iOS6. Skała i twarde miejsce?
Marc
@Marc Dodałem do mojej odpowiedzi, aby rozwiązać twoje obawy.
NJones
Dzięki. W mojej aplikacji może być całkiem sporo stwierdzeń If! Wydaje mi się, że to samo podejście może zadziałać przy użyciu właściwości „modalViewController”. Myślałem o utworzeniu kategorii, która zawierałaby ten kod, czy utworzenie kategorii w UIViewControler spowoduje odrzucenie?
Marc
Czy w przypadku kodu if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){ [self presentViewController:test animated:YES completion:nil]; } else { [self presentModalViewController:test animated:YES]; }istnieje sposób, aby ręcznie spowodować, że nie będzie wyświetlane ostrzeżenie kompilatora?
William Entriken
@FullDecent Tak, możesz. Zredagowałem odpowiedź, podając kilka informacji na ten temat.
NJones
6

Teraz w iOS 6 i nowszych możesz używać:

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

Zamiast:

[[Picker parentViewControl] dismissModalViewControllerAnimated:YES];

... i możesz użyć:

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

Zamiast

[self presentModalViewController:picker animated:YES];    
Dipang
źródło
4

[self dismissModalViewControllerAnimated:NO]; został wycofany.

Użyj [self dismissViewControllerAnimated:NO completion:nil];zamiast tego.

Jayprakash Dubey
źródło
4

Posługiwać się

[self dismissViewControllerAnimated:NO completion:nil];
Mak083
źródło
3

Ostrzeżenie wciąż tam jest. Żeby się go pozbyć, włożyłem go do takiego selektora:

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

Jest to korzystne dla osób z OCD, takich jak ja;)

kjoelbro
źródło
Należy zmienić instrukcję if, ponieważ uważam, że przestarzała metoda nie spowoduje respondsToSelectorzwrócenia wartości false. W związku z tym nowy dismissViewControllerAnimated:nie zostanie nigdy wywołany do czasu przyszłej aktualizacji, w której prawdopodobnie zostaną dismissModalViewControllerAnimated:całkowicie usunięte .
Jsdodgers
0

Oto odpowiednia wersja presentViewController, której użyłem, jeśli pomaga innym początkującym użytkownikom, takim jak ja:

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

Użyłem ViewController `` ogólnie '' i byłem w stanie sprawić, by widok modalny wyglądał inaczej w zależności od tego, do czego został wywołany (używając setHidden i setImage). i wcześniej wszystko działało dobrze, ale performSelector ignoruje rzeczy `` ustawione '', więc ostatecznie wydaje się, że jest to kiepskie rozwiązanie, jeśli spróbujesz być efektywny, tak jak ja ...

Walter
źródło