UIAlertView / UIAlertController兼容iOS 7和iOS 8

我正在使用Swift写一个应用程序,我需要显示一个警报。 该应用程序必须与iOS 7和iOS 8兼容。 由于UIAlertView已被replace为UIAlertController ,如何检查UIAlertController是否可用而不检查系统版本? 我一直听说苹果build议我们不要检查设备的系统版本,以确定API的可用性。

这是我正在使用的iOS 8,但这在iOS 7上崩溃与“ dyld: Symbol not found: _OBJC_CLASS_$_UIAlertAction ”:

 let alert = UIAlertController(title: "Error", message: message, preferredStyle: .Alert) let cancelAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil) alert.addAction(cancelAction) presentViewController(alert, animated: true, completion: nil) 

如果我使用iOS 8的UIAlertView,我得到这个警告: Warning: Attempt to dismiss from view controller <_UIAlertShimPresentingViewController: 0x7bf72d60> while a presentation or dismiss is in progress!

检测模式与Objective-C样式相同。

您需要检测当前的活动运行时是否具有实例化此类的能力

 if objc_getClass("UIAlertController") != nil { println("UIAlertController can be instantiated") //make and use a UIAlertController } else { println("UIAlertController can NOT be instantiated") //make and use a UIAlertView } 

不要试图根据操作系统版本来解决这个问题。 你需要检测不是操作系统的能力。

编辑

这个答案的原始检测器NSClassFromString("UIAlertController")-O优化下失败,所以它被更改为当前版本,它适用于发布版本

编辑2

NSClassFromString在Xcode 6.3 / Swift 1.2的所有优化工作

对于非Swift代码,纯粹的目标C做到这一点

 if ([UIAlertController class]) { // use UIAlertController UIAlertController *alert= [UIAlertController alertControllerWithTitle:@"Enter Folder Name" message:@"Keep it short and sweet" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action){ //Do Some action here UITextField *textField = alert.textFields[0]; NSLog(@"text was %@", textField.text); }]; UIAlertAction* cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { NSLog(@"cancel btn"); [alert dismissViewControllerAnimated:YES completion:nil]; }]; [alert addAction:ok]; [alert addAction:cancel]; [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = @"folder name"; textField.keyboardType = UIKeyboardTypeDefault; }]; [self presentViewController:alert animated:YES completion:nil]; } else { // use UIAlertView UIAlertView* dialog = [[UIAlertView alloc] initWithTitle:@"Enter Folder Name" message:@"Keep it short and sweet" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil]; dialog.alertViewStyle = UIAlertViewStylePlainTextInput; dialog.tag = 400; [dialog show]; } 

我非常恼火,不得不写出这两种情况,所以我写了一个适用于iOS 7的兼容UIAlertController,所以我只是把它扔在GitHub上。 我尽我所能复制了(更好的)添加UIAlertController的button和动作的方法。 适用于Objective-C和Swift。 当我在Google上search时发现这个问题,并发现这可能对其他人有用。

https://github.com/BayPhillips/compatible-alert-controller

您可以使用此代码解决您的问题: –

 var device : UIDevice = UIDevice.currentDevice()!; var systemVersion = device.systemVersion; var iosVerion : Float = systemVersion.bridgeToObjectiveC().floatValue; if(iosVerion < 8.0) { let alert = UIAlertView() alert.title = "Noop" alert.message = "Nothing to verify" alert.addButtonWithTitle("Click") alert.show() }else{ var alert : UIAlertController = UIAlertController(title: "Noop", message: "Nothing to verify", preferredStyle: UIAlertControllerStyle.Alert) alert.addAction(UIAlertAction(title: "Click", style:.Default, handler: nil)) self.presentViewController(alert, animated: true, completion: nil) } 

UIKit必须被标记为“可选”而不是“必需”。

Courtsey: – 可以在iOS 7和iOS 8上运行的警报

Swift 2.0

  if #available(iOS 8.0, *) { } else { } 

如果这是共享代码,并且可能在iOS 8扩展(UIAlertView和UIActionSheet是受限制的API)中使用代码,以及UIAlertController不存在的iOS 7,请查看: JVAlertController

它是UIAlertController到iOS 7的API兼容的后端,我承诺使SDK代码在iOS 7和iOS 8扩展中都是安全的。

你可以使用一个类来解决这个问题(尽pipe你需要把它转换成Swift):

 @implementation UIView( AlertCompatibility ) +( void )showSimpleAlertWithTitle:( NSString * )title message:( NSString * )message cancelButtonTitle:( NSString * )cancelButtonTitle { if( [[UIDevice currentDevice] isSystemVersionLowerThan: @"8"] ) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle: title message: message delegate: nil cancelButtonTitle: cancelButtonTitle otherButtonTitles: nil]; [alert show]; } else { // nil titles break alert interface on iOS 8.0, so we'll be using empty strings UIAlertController *alert = [UIAlertController alertControllerWithTitle: title == nil ? @"": title message: message preferredStyle: UIAlertControllerStyleAlert]; UIAlertAction *defaultAction = [UIAlertAction actionWithTitle: cancelButtonTitle style: UIAlertActionStyleDefault handler: nil]; [alert addAction: defaultAction]; UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController; [rootViewController presentViewController: alert animated: YES completion: nil]; } } @end @implementation UIDevice( SystemVersion ) -( BOOL )isSystemVersionLowerThan:( NSString * )versionToCompareWith { if( versionToCompareWith.length == 0 ) return NO; NSString *deviceSystemVersion = [self systemVersion]; NSArray *systemVersionComponents = [deviceSystemVersion componentsSeparatedByString: @"."]; uint16_t deviceMajor = 0; uint16_t deviceMinor = 0; uint16_t deviceBugfix = 0; NSUInteger nDeviceComponents = systemVersionComponents.count; if( nDeviceComponents > 0 ) deviceMajor = [( NSString * )systemVersionComponents[0] intValue]; if( nDeviceComponents > 1 ) deviceMinor = [( NSString * )systemVersionComponents[1] intValue]; if( nDeviceComponents > 2 ) deviceBugfix = [( NSString * )systemVersionComponents[2] intValue]; NSArray *versionToCompareWithComponents = [versionToCompareWith componentsSeparatedByString: @"."]; uint16_t versionToCompareWithMajor = 0; uint16_t versionToCompareWithMinor = 0; uint16_t versionToCompareWithBugfix = 0; NSUInteger nVersionToCompareWithComponents = versionToCompareWithComponents.count; if( nVersionToCompareWithComponents > 0 ) versionToCompareWithMajor = [( NSString * )versionToCompareWithComponents[0] intValue]; if( nVersionToCompareWithComponents > 1 ) versionToCompareWithMinor = [( NSString * )versionToCompareWithComponents[1] intValue]; if( nVersionToCompareWithComponents > 2 ) versionToCompareWithBugfix = [( NSString * )versionToCompareWithComponents[2] intValue]; return ( deviceMajor < versionToCompareWithMajor ) || (( deviceMajor == versionToCompareWithMajor ) && ( deviceMinor < versionToCompareWithMinor )) || (( deviceMajor == versionToCompareWithMajor ) && ( deviceMinor == versionToCompareWithMinor ) && ( deviceBugfix < versionToCompareWithBugfix )); } @end 

然后就打电话

 [UIView showSimpleAlertWithTitle: @"Error" message: message cancelButtonTitle: @"OK"]; 

但是,如果你不想检查系统版本,只需使用

 BOOL lowerThaniOS8 = NSClassFromString( @"UIAlertController" ) == nil; 

在类别UIView(AlertCompatibility)

如果您同时使用iOS 7- UIAlertView和iOS 8+ UIAlertController,并且希望您的UIAlertController块调用您的UIAlertView的委托(例如MyController)alertView:didDismissWithButtonIndex方法来继续处理结果,则下面是一个示例那:

 if ([UIAlertController class]) { MyController * __weak mySelf = self; UIAlertController *alertController = [UIAlertController alertControllerWithTitle:alertTitle message:alertMessage preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:alertCancel style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { [mySelf alertView:nil didDismissWithButtonIndex:0]; } ]; ... 

这使用苹果的build议,在一个块中捕获自己捕获自己时避免强参考循环

当然,这个方法假设你在控制器中只有一个UIAlertView,因此将其值作为委托方法传递给nil。 否则,您需要实例化(并标记)“假”UIAlertView传递给alertView:didDismissWithButtonIndex。

这里要检查UIAlertView和UIAlertContoller的两种方式。

检查1: iOS版本检查UIAlertController类。

  if #available(iOS 8.0, *) { // UIALertController let alert = UIAlertController(title: "Alert", message: "Alert after 8.0", preferredStyle: .Alert) let cancelAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil) alert.addAction(cancelAction) presentViewController(alert, animated: true, completion: nil) } else { // UIALertView UIAlertView(title: "Alert", message: "Alert below iOS V 8.0", delegate: nil, cancelButtonTitle: "OK").show() } 

检查2:检查UIAlertController零,然后在8.0以下的iOS版本。

  if objc_getClass("UIAlertController") != nil { // UIALertController let alert = UIAlertController(title: "Alert", message: "Alert after 8.0", preferredStyle: .Alert) let cancelAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil) alert.addAction(cancelAction) presentViewController(alert, animated: true, completion: nil) } else { // UIALertView UIAlertView(title: "Alert", message: "Alert below iOS V 8.0", delegate: nil, cancelButtonTitle: "OK").show() } 

如果你想与iOS 7兼容,就不要使用UIAlertController 。 就那么简单。

UIAlertView还没有被replace,它仍然完美,并将继续在可预见的未来完美的工作。

这里是我的拖放迅速解决scheme:

 //Alerts change in iOS8, this method is to cover iOS7 devices func CozAlert(title: String, message: String, action: String, sender: UIViewController){ if respondsToSelector("UIAlertController"){ var alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert) alert.addAction(UIAlertAction(title: action, style: UIAlertActionStyle.Default, handler:nil)) sender.presentViewController(alert, animated: true, completion: nil) } else { var alert = UIAlertView(title: title, message: message, delegate: sender, cancelButtonTitle:action) alert.show() } } 

这样的电话:

 CozAlert("reportTitle", message: "reportText", action: "reportButton", sender: self) 

当心这只是最基本的警报,你可能需要额外的代码高级的东西。

尝试下面的代码。 它适用于iOS 8及以下版本。

 if (IS_OS_8_OR_LATER) { UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { }]; [alertVC addAction:cancelAction]; [[[[[UIApplication sharedApplication] windows] objectAtIndex:0] rootViewController] presentViewController:alertVC animated:YES completion:^{ }]; } else{ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil]; [alert show]; } 

从这个链接下载警报类,并轻松地使用它的ios 6,7和8

 //Old code **UIAlertView** *alert=[[**UIAlertView** alloc]initWithTitle:@"FreeWare" message:@"Welcome to Common class" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil]; //New code **MyAlertView** *alert=[[**MyAlertView** alloc]initWithTitle:@"FreeWare" message:@"Welcome to Common class" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil]; 

在iOS8中,有一个新的类UIAlertControllerreplace了UIAlertViewUIActionSheet 。 从iOS8开始,使用UIAlertController和iOS8,之后使用UIAlertView和UIActionSheet。 我认为iOS8添加了改变UIAlertView显示方向的size classes 。 请参阅: https : //github.com/wangyangcc/FYAlertManage