UIAlertView/UIAlertController iOS 7 和 iOS 8 兼容性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25111011/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:41:37  来源:igfitidea点击:

UIAlertView/UIAlertController iOS 7 and iOS 8 compatibility

iosswiftuialertviewuialertcontroller

提问by Shan

I am using Swift to write an app and I need to show an alert. The app must be iOS 7 and iOS 8 compatible. Since UIAlertViewhas been replaced with UIAlertController, how can I check if the UIAlertControlleris available without checking the system version? I have been hearing that Apple recommends that we should not check the system version of the device in order to determine the availability of an API.

我正在使用 Swift 编写一个应用程序,我需要显示一个警报。该应用程序必须与 iOS 7 和 iOS 8 兼容。既然UIAlertView已经被替换了UIAlertController,如何在UIAlertController不检查系统版本的情况下检查是否可用?我一直听说 Apple 建议我们不要检查设备的系统版本来确定 API 的可用性。

This is what I am using for iOS 8 but this crashes on iOS 7 with "dyld: Symbol not found: _OBJC_CLASS_$_UIAlertAction" :

这是我在 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)

If I use the UIAlertView for iOS 8, I get this warning: Warning: Attempt to dismiss from view controller <_UIAlertShimPresentingViewController: 0x7bf72d60> while a presentation or dismiss is in progress!

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

回答by Warren Burton

The detection pattern is identical to the Objective-C style.

检测模式与 Objective-C 风格相同。

You need to detect whether the current active runtime has the ability to instantiate this class

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

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
}

Don't try and work out this based on the OS version. You need to detect abilities NOTOS.

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

EDIT

编辑

The original detector for this answer NSClassFromString("UIAlertController")fails under -Ooptimisation so its been changed to the current version which does work for Release builds

此答案的原始检测器NSClassFromString("UIAlertController")-O优化下失败,因此已更改为适用于发布版本的当前版本

EDIT 2

编辑 2

NSClassFromStringis working at all optimisations in Xcode 6.3/Swift 1.2

NSClassFromString正在 Xcode 6.3/Swift 1.2 中进行所有优化

回答by Sam B

For non-swift code, pure objective-C do this

对于非 swift 代码,纯 Objective-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];

    }

回答by Bay Phillips

I was annoyed that I kept having to write out both situations, so I wrote a compatible UIAlertController that works for iOS 7 as well so I just threw it up on GitHub. I did my best to replicate the (much better) methods of adding buttons and actions of the UIAlertController. Works with both Objective-C and Swift. I'm posting this as I found this question when searching on Google and figured it could be helpful for others.

我很恼火,我一直不得不写出这两种情况,所以我写了一个兼容的 UIAlertController,它也适用于 iOS 7,所以我把它扔到了 GitHub 上。我尽力复制了添加 UIAlertController 按钮和操作的(更好)方法。适用于 Objective-C 和 Swift。我发布这个是因为我在谷歌上搜索时发现了这个问题,并认为它可能对其他人有帮助。

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

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

回答by Shivaay

You can resolve your issue using this code :-

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

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)
        }

and UIKit had to be marked Optional rather than Required.

并且 UIKit 必须被标记为 Optional 而不是 Required。

Courtsey :- Alert that can work on iOS 7 and iOS 8

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

回答by William Hu

Swift 2.0

斯威夫特 2.0

 if #available(iOS 8.0, *) {

 } else {

 }

回答by jverdi

If this is shared code, and there is the possibility that the code can be used in an iOS 8 extension (where UIAlertView and UIActionSheet are restricted APIs) as well as iOS 7, where UIAlertController does not exist, have a look at: JVAlertController

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

It is an API-compatible back-port of UIAlertController to iOS 7, that I undertook to make SDK code safe for use in both iOS 7 and iOS 8 extensions.

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

回答by ScottyB

If your using both iOS 7- UIAlertView and iOS 8+ UIAlertController as described above, and you want your UIAlertController blocks to call your UIAlertView's delegate (e.g. MyController) alertView:didDismissWithButtonIndex method to continue processing the results, here is an example of how to do that:

如果您同时使用 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];
            }
    ];

...

This uses Apple's recommendation for capturing selfin a block: Avoid Strong Reference Cycles when Capturing self

这使用了 Apple在块中捕获self的建议:Avoid Strong Reference Cycles when Capture self

Of course, this method assumes you only have one UIAlertView in the controller and therefore pass nil as its value to the delegate method. Otherwise, you'd need to instantiate (and tag) a "fake" UIAlertView to pass to alertView:didDismissWithButtonIndex.

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

回答by Daniel Alves

You could use a category to solve that (though you'll need to convert it to Swift):

您可以使用类别来解决该问题(尽管您需要将其转换为 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

Then just call

然后只需调用

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

But, if you do not want to check the system version, just use

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

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

inside the category UIView( AlertCompatibility )

在类别 UIView( AlertCompatibility ) 内

回答by Kirit Modi

Here to check two way of UIAlertViewand UIAlertContoller.

在这里检查UIAlertViewUIAlertContoller 的两种方式。

Check 1 :iOS verstion check UIAlertControllerClass.

检查 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()
    }

Check 2 :check UIAlertControllernil then iOS version below 8.0.

检查 2:检查UIAlertControllernil 然后检查低于 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()
    }

回答by Esqarrouth

Here is my drag and drop swift solution:

这是我的拖放快速解决方案:

//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()
    }
}

Call like this:

像这样调用:

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

Beware this is only for the most basic alerts, you might need additional code for advanced stuff.

请注意,这仅适用于最基本的警报,对于高级内容,您可能需要额外的代码。