如果是iOS 8及以上版本,使用UIAlertController,否则使用UIAlertView。

27

由于UIAlertView现在已被弃用,我希望使用iOS 8中使用的UIAlertController。是否有一种方法可以在不破坏对iOS 7支持的情况下使用它?是否可以进行某种if条件检查以检查iOS 8,否则为iOS 7支持执行其他操作?


请注意 - 由于您的部署目标是iOS 7(或更早版本),因此您可以直接使用UIAlertView。这将使您的代码更简单。 - rmaddy
2
我不知道Swift有一个respondsToSelector... 另外,UIAlertView在iOS8中出现了问题,它不能滚动,而在iOS7中可以,这就是为什么我想尝试同时使用两者的原因。 - Rocky Pulley
1
UIAlertController 上的滚动也不起作用。 - jcesarmobile
11个回答

99

我认为一个更好的检查类是否存在的方法(自从iOS 4.2起)是:

if([ClassToBeChecked class]) {

   // use it

} else {

  // use alternative

}

在你的情况下,那将是:

if ([UIAlertController class]) {
   // use UIAlertController

} else {
  // use UIAlertView

}

9
应将此标记为正确答案。始终检查类/特征/常量/函数的存在性,而不是检查iOS版本。 - Vilém Kurz
1
如何在Swift上实现? - ChikabuZ
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - mitrenegade
2
好的,因此@huey不应该尝试在xcode 5上进行编译。他需要使用xcode 6并使用您的代码来防止在设备使用ios7时调用UIAlertController。我的评论是为了指出无法编译的原因是该类在ios 7 sdk上不可用。但是,您的第一个回答说它将适用于ios7和xcode 5,如果该类不可用,则不是真的。 - mitrenegade
我的做法是参考开发者文档并相应编写代码。例如,在iOS 8中,UIActionSheet已被弃用,建议使用UIAlertController,但[UIActionSheet class]在iOS 8中仍会返回true。如果有疑问,请阅读文档以查看API,并检查代码中的操作系统版本和类的存在情况,以便进行最佳实践(防御性编程)。 - Hahnemann
显示剩余7条评论

12

Objective C(如上所述)

if ([UIAlertController class]) {
    // use UIAlertController

} else {
    // use UIAlertView

}

快速

if objc_getClass("UIAlertController") == nil  {
       // use UIAlertView 

} else {
  // use UIAlertController

}

请不要使用if NSClassFromString("UIAlertController") == nil,因为此方法的签名是func NSClassFromString(_ aClassName: String!) -> AnyClass!,所以它无法正常工作。


4
请看下面我认为最好的答案,由Erwan提供。
--
您可以像这样检查iOS版本以使用适当的控件:
if (([[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending)) {
    // use UIAlertView
}
else {
    // use UIAlertController
}

2
我在下面发布了我认为更好的方法,检查类是否存在而不是检查操作系统的版本。 - Erwan
3
这种检查的方式很脆弱。实际上,苹果公司不建议使用这种检查方式。Erwan 给出的回答是正确的。 - squarefrog
在代码中,我们永远不应该根据版本号进行检查,这是非常糟糕的做法。正如squarefrog所指出的那样,@Erwan提供了更好的解决方案,应该始终根据能力/特性进行检查。 - SHaKie
如上所述,条件评估[UIAlertController类]是首选策略。 如果需要检查操作系统的版本,则首选约定是比较NSFoundationVersionNumber - 详细信息请参见此处:https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TransitionGuide/SupportingEarlieriOS.html#//apple_ref/doc/uid/TP40013174-CH14-SW3 - Mark

3

正如其他人已经提到的-始终检查功能是否存在。我认为最安全的方法是遵循以下步骤:

if (NSClassFromString(@"UIAlertController")) {
    // use UIAlertController
} else {
    // use UIAlertView
}

当然存在输入错误的类名风险。 :)

NClassFromString 的文档中:

[返回] 名为 aClassName 的类对象,如果当前没有该名称的类,则返回 nil。如果 aClassName 为 nil,则返回 nil。

iOS(2.0 及更高版本)可用


1
这段代码片段在转换成 Swift 后,在 iOS 模拟器上运行正常,使用的是iOS 7.1 和 8.2。但是如果你在真实的 iOS 7.1 设备上测试,你会不幸地发现你永远无法通过代码片段中的 else 部分。所以,这段代码不稳定,我不建议在生产环境中使用它。 - King-Wizard
alino-91 的评论是正确的。使用 objc_getClass。 - thomasdao

2
使用 Swift 检查 iOS 版本的解决方案。
switch (UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch)) {
    case .OrderedAscending:
       println("iOS < 8.0")

    case .OrderedSame, .OrderedDescending:
       println("iOS >= 8.0")
}

这个解决方案的缺点是:无论你怎么做,检查操作系统版本号都是一种不好的做法。我们永远不应该以这种方式硬编码依赖项,而应该始终检查功能、能力或类的存在性。考虑一下:苹果可能会发布一个向后兼容的类版本,如果他们这样做了,那么您提出的代码将永远不会使用它,因为您的逻辑寻找的是操作系统版本号,而不是类的存在性。 此信息来源 在Swift中检查类是否存在的解决方案
if (objc_getClass("UIAlertController") == nil) {
   // iOS 7
} else {
   // iOS 8+
}

不要使用if (NSClassFromString("UIAlertController") == nil),因为它在使用iOS 7.1和8.2的iOS模拟器上可以正常工作,但是如果你在使用iOS 7.1的真实设备上测试,你会不幸地发现你永远无法通过代码片段的else部分。

不要使用 if (NSClassFromString("UIAlertController") == nil),因为它在使用 iOS 7.1 和 8.2 的 iOS 模拟器上可以正常工作,但是如果你在使用 iOS 7.1 的真实设备上进行测试,你会不幸地发现你永远无法通过代码片段的 else 部分。这是真的。我希望我之前读过这个。 - thomasdao

1

我已经用Objective-C创建了一个非常简单的包装器,支持旧的iOS UIAlertView和新的UIAlertViewController。

https://github.com/MartinPerry/UIAlert/

它还使旧的UIAlertView使用新的操作块。
示例:
MyAlertMessage * a = [[MyAlertMessage alloc] initWithTitle:@"Hello" WithMessage:@"World"];

[a addButton:BUTTON_OK WithTitle:@"OK" WithAction:^(void *action) { 
  NSLog(@"Button OK at index 0 click"); 
}];

[a addButton:BUTTON_CANCEL WithTitle:@"Cancel" WithAction:^(void *action) {
  NSLog(@"Button Cancel at index 1 click"); 
}];

[a show];

这个处理多个警报吗? - palme

1
创建简单的实用函数以减少代码
代码:
// pass minimum required iOS version
BOOL isOSSupported(NSString *minRequiredVersion)
{
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    BOOL isOSSupported = ([currSysVer compare:minRequiredVersion options:NSNumericSearch] != NSOrderedAscending) && 
                                  ![currSysVer isEqualToString:@"Unknown"];
    return isOSSupported;
}

"USE:"
if(isOSSupported("8.0")
{
// Code for iOS8 and above
}
else
{
// Code for iOS7 and below
}



或者使用系统常量NSFoundationVersionNumber_iOS_7_1,如下所示

if(floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1)
{
   // Code for iOS8 and above
}
else
{
   // Code for iOS7 and below
}


更多选项请访问链接


1
没有必要使用-1 :)),做这件事的人请与他人分享您的想法。 - Jageen
不良做法,永远不要根据版本号进行检查。始终根据能力/功能进行检查。 - SHaKie
@SHaKie 那么,在哪种情况下使用苹果提供的常量NSFoundationVersionNumber_iOS_7_1是有益的呢? - Jageen
最佳实践是检查类是否存在,就像我在上面发布的答案一样。对于方法,你还可以检查类是否响应@selector(yourMethod)。 - Erwan
@Jageen,恐怕不行。无论如何,根据操作系统版本号进行检查都是不好的做法。我们永远不应该以这种方式硬编码依赖项,而应该始终检查功能、能力或类的存在。请考虑一下:苹果可能会发布一个向后兼容的类版本,如果他们这样做了,那么你建议的代码将永远不会使用它,因为你的逻辑寻找的是操作系统版本号,而不是类的存在。 - SHaKie

1
// Above ios 8.0
float os_version = [[[UIDevice currentDevice] systemVersion] floatValue];
if (os_version >= 8.000000)
{
      //Use UIAlertController    
}
else
{
     //UIAlertView
}

1
我已经编写了一个类,它包装了UIAlertView并使用UIAlertController。对于程序员来说,这是透明的,因此只需将这些类导入项目中即可。这些类的实用性在于当旧项目中有多个UIAlertView需要更改时。链接: https://github.com/kennymuse/UIAlertView

0

方法一

通过 iOS 系统版本检查

#define iOSVersionLessThan(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
// below ios8 ,create UIAlertView
if(iOSVersionLessThan(@"7.0")){
     // todo

// ios8 and above ,UIActionController avaliable
}else{
    // todo
}

方法二

通过系统特性检测

// create UIActionController 
if([UIActionController class]){
    // todo
// create UIAlertView
}else{
    // todo
}

但是,还有一个名为PSTAlertController的第三方库,可以处理与UIActionSheet和UIAlertView向后兼容到iOS 7的问题。

参考


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接