104

我刚刚升级到 XCode 4.5 以更新我的 iOS 应用程序以在 iPhone 5 的 4 英寸显示屏上运行,但我收到了一个构建错误,提示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')

谢谢!

4

6 回答 6

306

新方法是:

[self dismissViewControllerAnimated:NO completion:nil];

模态一词已被删除;就像呈现 API 调用一样:

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

原因在2012 WWDC Session 236 - The Evolution of View Controllers on iOS Video 中进行了讨论。本质上,这个 API 提供的视图控制器不再总是模态的,并且由于它们添加了一个完成处理程序,因此是重命名它的好时机。

回应马克的评论:

支持所有设备 4.3 及更高版本的最佳方式是什么?新方法在 iOS4 中不起作用,但旧方法在 iOS6 中已弃用。

我意识到这几乎是一个单独的问题,但我认为值得一提,因为不是每个人都有钱每 3 年升级一次所有设备,所以我们中的许多人都有一些旧的(5.0 之前的)设备。尽管如此,尽管我说起来很痛苦,但您需要考虑是否值得将其定位在 5.0 以下。在 5.0 以下,有许多新的很酷的 API 不可用。Apple 不断加大针对他们的难度;例如,从 Xcode 4.5 中删除了 armv6 支持。

要低于 5.0(只要完成块为 nil),只需使用方便的respondsToSelector: 方法。

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

回应 Marc 的另一条评论:

在我的应用程序中可能有很多 If 语句!...我正在考虑创建一个封装此代码的类别,在 UIViewControler 上创建一个类别会让我被拒绝吗?

还有一个来自Full Decent:

...有没有办法手动使其不显示编译器警告?

首先,不,在其本身上创建一个类别UIViewController不会让您的应用被拒绝;除非该类别方法称为私有 API 或类似的东西。

类别方法对于此类代码来说是一个非常好的地方。此外,由于只有一次对已弃用 API 的调用,因此只有一个编译器警告。

要解决 Full Decent 的评论(问题),是的,您可以手动禁止编译器警告。这是关于该主题的 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
于 2012-09-16T07:45:04.400 回答
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];    
于 2012-10-04T08:52:59.743 回答
4

[self dismissModalViewControllerAnimated:NO];已被弃用。

改为使用[self dismissViewControllerAnimated:NO completion:nil];

于 2013-04-19T06:02:46.410 回答
4

采用

[self dismissViewControllerAnimated:NO completion:nil];
于 2013-10-04T11:52:26.017 回答
3

警告仍然存在。为了摆脱它,我将它放入这样的选择器中:

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

它使像我这样的强迫症患者受益;)

于 2013-04-18T13:49:59.570 回答
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,并且能够使模态视图以不同的方式显示,具体取决于它被调用的操作(使用 setHidden 和 setImage)。以前一切都很好,但是 performSelector 忽略了“设置”的东西,所以如果你试图像我试图成为的那样高效,最终它似乎是一个糟糕的解决方案......

于 2013-04-26T21:34:33.163 回答