UIAlertView/UIAlertController iOS 7 and iOS 8 compatibility

后端 未结 14 1493
暗喜
暗喜 2020-11-28 22:31

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 UIAlertView has been replaced with UIAlert

相关标签:
14条回答
  • 2020-11-28 22:51

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

    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 NOT OS.

    EDIT

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

    EDIT 2

    NSClassFromString is working at all optimisations in Xcode 6.3/Swift 1.2

    0 讨论(0)
  • 2020-11-28 22:53

    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.

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

    0 讨论(0)
  • 2020-11-28 22:53

    If you want to be compatible with iOS 7, just don't use UIAlertController. Simple as that.

    UIAlertView has not been replaced, it still works perfectly and will continue to work perfectly for the foreseeable future.

    0 讨论(0)
  • 2020-11-28 22:55

    You could use a category to solve that (though you'll need to convert it to 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 )

    0 讨论(0)
  • 2020-11-28 22:56

    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:

    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 self in a block: Avoid Strong Reference Cycles when Capturing 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.

    0 讨论(0)
  • 2020-11-28 22:58

    Swift 2.0

     if #available(iOS 8.0, *) {
    
     } else {
    
     }
    
    0 讨论(0)
提交回复
热议问题