Уклонение от отклонения

Я только что обновился до 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')

Спасибо!

Ответ 1

Новый метод:

[self dismissViewControllerAnimated:NO completion:nil];

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

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

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

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

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

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

Чтобы настроить таргетинг ниже 5.0 (до тех пор, пока блок завершения равен нулю), просто используйте удобный respondsToSelector: метод.

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

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

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

и один из полного подтверждения:

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

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

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

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

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

@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

Теперь в 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

[self dismissModalViewControllerAnimated:NO]; устарел.

Используйте [self dismissViewControllerAnimated:NO completion:nil]; вместо этого.

Ответ 4

Используйте

[self dismissViewControllerAnimated:NO completion:nil];

Ответ 5

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

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

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

Ответ 6

Вот соответствующая версия 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 "в общем" и смог получить модальный вид, чтобы выглядеть по-другому в зависимости от того, что он вызывал (используя setHidden и setImage). и все хорошо работало раньше, но PerformSelector игнорирует "набор", поэтому, в конце концов, это плохое решение, если вы пытаетесь быть эффективным, как я пытался...