dismissModalViewControllerAnimated устарело


103

Я только что обновился до XCode 4.5, чтобы обновить свое приложение iOS для работы на 4-дюймовом дисплее iPhone 5, но я получаю сообщение об ошибке сборки dismissModalViewControllerAnimated:' is deprecatedв строке:

[self dismissModalViewControllerAnimated:NO];

Я пробовал выполнить обновление до рекомендованной перегрузки с помощью обработчика завершения (но для него установлено значение NULL) следующим образом:

[self dismissModalViewControllerAnimated:NO completion:NULL];

Но тогда эта строка выдает две ошибки:

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

Спасибо!

Ответы:


307

Новый метод:

[self dismissViewControllerAnimated:NO completion:nil];

Слово модальное было удалено; Как это было для вызова API представления:

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

Причины обсуждались в 2012 WWDC Session 236 - Эволюция контроллеров представления в iOS Video. По сути, контроллеры представлений, представленные этим API, больше не всегда являются модальными, и, поскольку они добавляли обработчик завершения, это было хорошее время для его переименования.

В ответ на комментарий Марка:

Как лучше всего поддерживать все устройства 4.3 и выше? Новый метод не работает в iOS4, но старый метод устарел в iOS6.

Я понимаю, что это почти отдельный вопрос, но я думаю, что об этом стоит упомянуть, поскольку не у всех есть деньги на обновление всех своих устройств каждые 3 года, поэтому у многих из нас есть старые (до 5.0) устройства. Тем не менее, как бы мне ни было больно об этом говорить, вам нужно подумать, стоит ли устанавливать таргетинг ниже 5.0. Есть много новых интересных API, недоступных ниже 5.0. И Apple постоянно затрудняет их нацеливание; Например, поддержка armv6 исключена из Xcode 4.5.

Чтобы настроить таргетинг ниже 5,0 (пока блок завершения равен нулю), просто используйте handy respondsToSelector: method.

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

В ответ на еще один комментарий Марка:

В моем приложении может быть довольно много операторов If! ... Я думал о создании категории, которая инкапсулирует этот код, может ли создание категории в UIViewControler привести меня к отказу?

и один от Full Decent:

... есть ли способ вручную заставить это не отображать предупреждение компилятора?

Во-первых, нет, создание категории UIViewControllerсамо по себе не приведет к отклонению вашего приложения; если этот метод категории не называет частные API или что-то подобное.

Категориальный метод - очень хорошее место для такого кода. Кроме того, поскольку будет только один вызов устаревшего API, будет только одно предупреждение компилятора.

Чтобы ответить на комментарий (вопрос) Full Decent, да, вы можете вручную подавить предупреждения компилятора. Вот ссылка на ответ по этому поводу . Метод категории также является отличным местом для подавления предупреждения компилятора, поскольку вы подавляете предупреждение только в одном месте. Вы, конечно же, не захотите волей-неволей заставить компилятор замолчать.

Если бы мне пришлось написать для этого простой метод категорий, это могло бы быть примерно так:

@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

2
Как лучше всего поддерживать все устройства 4.3 и выше? Новый метод не работает в iOS4, но старый метод устарел в iOS6. Рок и наковальня?
Marc,

@Marc Я добавил в свой ответ, чтобы снять вашу озабоченность.
NJones

Спасибо. В моем приложении может быть довольно много операторов If! Думаю, тот же подход может работать при использовании свойства modalViewController. Я думал о создании категории, которая инкапсулирует этот код, будет ли создание категории в UIViewControler отклонить меня?
Marc

Для кода if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){ [self presentViewController:test animated:YES completion:nil]; } else { [self presentModalViewController:test animated:YES]; }есть способ вручную заставить это не отображать предупреждение компилятора?
Уильям Энтрикен,

@FullDecent Да, можно. Я отредактировал свой ответ, добавив некоторую информацию по этому поводу.
NJones

6

Теперь в iOS 6 и выше вы можете использовать:

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

Вместо того:

[[Picker parentViewControl] dismissModalViewControllerAnimated:YES];

... И вы можете использовать:

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

Вместо того

[self presentModalViewController:picker animated:YES];    



3

Предупреждение все еще существует. Чтобы избавиться от него, я помещаю его в такой селектор:

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

Это приносит пользу людям с ОКР, таким как я;)


Вы должны переключить оператор if, потому что я считаю, что устаревший метод не приведет respondsToSelectorк возврату false. Таким образом, новые dismissViewControllerAnimated:никогда не будут вызываться до следующего обновления, из которого они, возможно, будут dismissModalViewControllerAnimated:полностью удалены .
Jsdodgers

0

Вот соответствующая версия PresentViewController, которую я использовал, если она помогает другим новичкам, таким как я:

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

Я использовал ViewController «в общем» и смог заставить модальный View выглядеть по-разному в зависимости от того, для чего он был вызван (с помощью setHidden и setImage). и раньше все работало хорошо, но PerformSelector игнорирует 'set', так что, в конце концов, это кажется плохим решением, если вы пытаетесь быть эффективным, как я пытался быть ...

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.