dismissModalViewControllerAnimated przestarzałe

Właśnie zaktualizowałem XCode 4.5, aby zaktualizować moją aplikację iOS do działania na 4-calowym wyświetlaczu dla iPhone'a 5, ale pojawia się błąd kompilacji, który mówidismissModalViewControllerAnimated:' is deprecated na linii:

[self dismissModalViewControllerAnimated:NO];

Próbowałem zaktualizować zalecane przeciążenie za pomocą procedury obsługi uzupełniania (ale ustawiono na NULL) w następujący sposób:

[self dismissModalViewControllerAnimated:NO completion:NULL];

Ale wtedy ta linia zgłasza 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!

questionAnswers(6)

QuestionSolution

Nowa metoda to:

[self dismissViewControllerAnimated:NO completion:nil];

Słowomodalny zostało usunięte; Tak jak w przypadku prezentacji interfejsu API:

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

Powody zostały omówione wSesja WWDC 2012 236 - Ewolucja kontrolerów widoku na iOS Wideo. Zasadniczo kontrolery widoku prezentowane przez ten interfejs API nie są już zawsze modalne, a ponieważ dodawały program obsługi zakończenia, dobrze było go zmienić.

W odpowiedzi na komentarz Marca:

Jaki jest najlepszy sposób obsługi 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 wspomnieć, ponieważ nie każdy ma pieniądze na aktualizację wszystkich swoich urządzeń co 3 lata, więc wielu z nas ma starsze (przed 5.0) urządzenia. Mimo to, jakkolwiek boli mnie to, muszę się zastanowić, czy warto celować poniżej 5,0. Istnieje wiele nowych i fajnych interfejsów API niedostępnych poniżej wersji 5.0. A Apple nieustannie utrudnia dotarcie do nich; Wsparcie dla armv6 jest odrzucane na przykład z Xcode 4.5.

Aby celować poniżej 5,0 (tak długo, jak blok ukończenia jest zerowy), użyj poręcznegorespondsToSelector: metoda.

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

W odpowiedzi na kolejny komentarz Marca:

To może być całkiem sporo instrukcji If w mojej aplikacji! ... Myślałem o stworzeniu kategorii, która zawierałaby ten kod, czy utworzenie kategorii w UIViewControler mnie odrzuciło?

a jeden z pełnego przyzwoitości:

... czy istnieje sposób ręcznego spowodowania, że ​​nie przedstawi ostrzeżenia kompilatora?

Po pierwsze, nie, tworząc kategorięUIViewController sama aplikacja nie zostanie odrzucona; chyba że ta kategoria nazywa prywatnymi API lub czymś podobnym.

Metoda kategorii to wyjątkowo dobre miejsce na taki kod. Ponadto, ponieważ będzie tylko jedno wywołanie przestarzałego API, będzie tylko jedno ostrzeżenie kompilatora.

Aby odpowiedzieć na komentarz Full Decent (pytanie), tak, możesz ręcznie wyłączyć ostrzeżenia kompilatora.Oto link do odpowiedzi na SO na ten temat. Metoda kategorii jest również świetnym miejscem do powstrzymania ostrzeżenia kompilatora, ponieważ ostrzeżenie jest wyłączane tylko w jednym miejscu. Z pewnością nie chcesz chodzić, uciszając kompilator chcąc nie chcąc.

Gdybym miał napisać prostą metodę kategorii, może to być coś takiego:

@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
 Jason McCreary04 wrz 2013, 17:41
Czy odbiornik powinien się zmieniać w zależności od tego, gdzie jest to wywoływane? To znaczy, możesz użyćpresentingViewController?
 NJones26 wrz 2012, 01:14
@Marc Dodałem do mojej odpowiedzi, aby rozwiązać twój problem.
 NJones22 maj 2013, 16:08
@ FullDecent Tak, możesz. Zmodyfikowałem swoją odpowiedź, podając kilka informacji na ten temat.
 Marc26 wrz 2012, 10:44
Dzięki. W mojej aplikacji może to być sporo oświadczeń If! Sądzę, że to samo podejście może działać, gdy używana jest właściwość „modalViewController”. Myślałem o stworzeniu kategorii, która zawierałaby ten kod, czy utworzenie kategorii na UIViewControler mnie odrzuciło?
 William Entriken21 maj 2013, 00:11
Dla koduif ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){ [self presentViewController:test animated:YES completion:nil]; } else { [self presentModalViewController:test animated:YES]; } Czy istnieje sposób ręcznego spowodowania, że ​​nie przedstawi ostrzeżenia kompilatora?
 Marc24 wrz 2012, 18:30
Jaki jest najlepszy sposób obsługi 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?
 NJones22 wrz 2013, 17:03
@JasonMcCreary Ogólnie możesz po prostu użyć[self dismiss… i automatycznie przejdzie dopresentingViewController. Wyjątkiem jest sytuacja, w której prezentowanych jest wiele kontrolerów widoku (w sposób znany wcześniej jako modalny); jeśli jest to przypadek, celujesz wdismiss… wywołanie kontrolera widoku, którego widok chcesz pozostawić po zwolnieniu, wszystkie powyższe widoki zostaną natychmiast odrzucone.

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

[self dismissModalViewControllerAnimated:NO]; został przestarzały.

Posługiwać się[self dismissViewControllerAnimated:NO completion:nil]; zamiast.

Posługiwać się

[self dismissViewControllerAnimated:NO completion:nil];

umieściłem go w selektorze takim jak ten:

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

Przynosi korzyści ludziom z OCD jak ja;)

 Jsdodgers28 lip 2013, 00:25
Należy zmienić instrukcję if, ponieważ uważam, że przestarzała metoda nie spowodujerespondsToSelector zwrócić false. Tak więc nowydismissViewControllerAnimated: nigdy nie zostanie wywołany, dopóki nie zostanie zaktualizowana w przyszłości, gdzie mogą zostać usuniętedismissModalViewControllerAnimated: całkowicie.

której użyłem, jeśli pomaga innym początkującym, 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 udało mi się uzyskać widok modalny, aby wyglądał inaczej, w zależności od tego, do czego został wywołany (używając setHidden i setImage). i wszystko działało dobrze wcześniej, ale performSelector ignoruje rzeczy „ustawione”, więc w końcu wydaje się, że jest to kiepskie rozwiązanie, jeśli próbujesz być wydajny, jak próbowałem być ...

yourAnswerToTheQuestion