33

I currently have the following line of code in one of my apps. It is a simple UIAlertView. However, as of iOS 8, this is now deprecated:

let alertView = UIAlertView(title: "Oops!", message: "This feature isn't available right now", delegate: self, cancelButtonTitle: "OK")

How do I update this to work with iOS 8+? I believe I have to change something to UIAlertCotroller, though I'm not too sure what.

Ky -
  • 30,724
  • 51
  • 192
  • 308
Dom Bryan
  • 1,238
  • 2
  • 19
  • 39
  • 2
    Use `UIAlertController` – Ashish Kakkad Jun 19 '15 at 08:56
  • 2
    This is not very helpful, can you explain how to use UIAlertController. It is not just a case of swap the word view out for controller – Dom Bryan Jun 19 '15 at 08:58
  • @Bhavin That happens with every framework. API that is old has to be sometimes replaced by better API. It's not like `UIAlert` is being removed now. We will still have it for a few releases until it will get removed completely. – Sulthan Jun 19 '15 at 09:19

8 Answers8

65

You need to use UIAlertController instead. To class documentation is pretty straightforward, even containing an usage example in Listing 1 at the very beginning of the doc (sure it's in ObjC and not in Swift but it's quite similar).

So for your use case, here is how it translates to (with added comments):

let alert = UIAlertController(title: "Oops!", message:"This feature isn't available right now", preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .default) { _ in
  // Put here any code that you would like to execute when
  // the user taps that OK button (may be empty in your case if that's just
  // an informative alert)
}
alert.addAction(action)
self.presentViewController(alert, animated: true){}

So the compact code will look like:

let alert = UIAlertController(title: "Oops!", message:"This feature isn't available right now", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default) { _ in })
self.present(alert, animated: true){}

Where self here is supposed to be your UIViewController.


Additional tip: if you need to call that code that displays the alert outside of the context of an UIViewController, (where self is not an UIViewController) you can always use the root VC of your app:

let rootVC = UIApplication.sharedApplication().keyWindow?.rootViewController
rootVC?.presentViewController(alert, animated: true){}

(But in general it's preferable to use a known UIViewController when you have one — and you generally present alerts from UIViewControllers anyway — or try to get the most suitable one depending on your context instead of relying on this tip)

Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150
AliSoftware
  • 32,623
  • 6
  • 82
  • 77
  • 3
    Of course not, as `UIAlertController` was introduced in iOS8. – AliSoftware Jul 21 '15 at 07:16
  • @AiSoftware then, perhaps, this is not a good way to migrate. It will deny the update for your current users, and rip the app from your potential users, who are still using iOS ≤ 7. – Ky - Jul 21 '15 at 15:34
  • 2
    What do you mean "it will deny the update for users on iOS ≤ 7"? (1) If your app is written in Swift as the code of the OP is, it won't run on iOS <7 anyway and (2) you can use this code conditionally (`if #available(iOS 8.0)` in Swift, `if ([UIAlertController class])` on Objective-C)… and fallback to `UIAlertView` if it's not available — That's what we always do when using new APIs anyway, as described in Apple's "SDK Compatibility Guide" (and always how you should migrate when still needing to support old OS versions, so nothing new here). – AliSoftware Jul 21 '15 at 16:46
  • For more information on supporting multiple OS versions, you can find a lot of useful info in [this Apple doc](https://developer.apple.com/library/ios/documentation/DeveloperTools/Conceptual/cross_development/Introduction/Introduction.html#//apple_ref/doc/uid/10000163-BCICHGIE). In short, you can use `UIAlertController` when the user is running iOS8 and still be compatible with iOS7 by using UIAlertViewController as a fallback in such cases. – AliSoftware Jul 21 '15 at 16:51
  • 1
    Writing in Swift, you're writing an iOS 8 app, where UIAlertView is already deprecated and UIAlertController already exists, and so there's no migration problem because you start with the new one. This question is `How do I migrate from UIAlertView (deprecated in iOS8)`, meaning that the app is old enough to have used UIAlertView in iOS 7, but is now moving to iOS 8. I don't know how OP found himself in this situation on a Swift app, but that's moot. – Ky - Jul 21 '15 at 19:21
  • is this still working for Swift 2.0? I just copied and pasted the code into my app; and I see no alert? Oops indeed?? – user3069232 Feb 08 '16 at 14:46
  • Probably because the keyWindow is nil in your case, so if you used it to guess what ViewController to present your alert on, of course this will present on nothing (well not present at all). I'd suggest to never try to guess the ViewController especially using UIApplication's keyWindow?.rootViewController, but rather explicitly use a known viewController known to exist (instead of trying to dig up into the sharedApplication, which would be a bad practice of crossing object responsibility boundaries anyway) – AliSoftware Feb 09 '16 at 21:14
  • for ios>8 let rootVC = UIApplication.shared.keyWindow?.rootViewController rootVC?.present(alert, animated: true){} – μολὼν.λαβέ Feb 15 '18 at 00:32
34

For those wondering on how to do this in Objective-C:

    //Step 1: Create a UIAlertController
    UIAlertController *myAlertController = [UIAlertController alertControllerWithTitle:@"MyTitle"
                                                              message: @"MyMessage"
                                                              preferredStyle:UIAlertControllerStyleAlert                   ];

    //Step 2: Create a UIAlertAction that can be added to the alert
    UIAlertAction* ok = [UIAlertAction
                         actionWithTitle:@"OK"
                         style:UIAlertActionStyleDefault
                         handler:^(UIAlertAction * action)
                         {
                             //Do some thing here, eg dismiss the alertwindow
                             [myAlertController dismissViewControllerAnimated:YES completion:nil];

                         }];

    //Step 3: Add the UIAlertAction ok that we just created to our AlertController
    [myAlertController addAction: ok];

    //Step 4: Present the alert to the user
    [self presentViewController:myAlertController animated:YES completion:nil];

This will pop-up an alert that looks like this:

alert example

RWIL
  • 8,729
  • 1
  • 28
  • 37
  • 1
    This is a great answer for the Objective C, but no need to dismiss the alert in the handler. This is done automatically. – jsgoupil Aug 31 '16 at 19:35
  • This is a great answer, but how do we handle the handler? I don't want to use embedded lambda but an external function common to more than one alertAction – Marin Dec 09 '20 at 16:50
4
let alertView = UIAlertView(title: "Oops!", message: "This feature isn't available right now", delegate: self, cancelButtonTitle: "OK")

becomes

let alertController = UIAlertController(title: "Oops!", message: "This feature isn't available right now", preferredStyle: .Alert)
let OKAction = UIAlertAction(title: "OK", style: .Default) { (action) in }
alertController.addAction(OKAction)
self.presentViewController(alertController, animated: true) { }
Miknash
  • 7,888
  • 3
  • 34
  • 46
2

I think this is the way to have backward compatibility for older iOS SDK and to use new API when using newer SDK. Also it is without warnings for deprecation in code using deprecated class.

    if ([UIAlertController class]) {
        // Use new API to create alert controller, add action button and display it
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"CityBoard" message:error.errorDescription preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction* ok = [UIAlertAction actionWithTitle: @"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
            [alertController dismissViewControllerAnimated:YES completion:nil];
        }];
        [alertController addAction: ok];
        [self presentViewController:alertController animated:YES completion:nil];
    } else {
        // We are running on old SDK as the new class is not available
        // Hide the compiler errors about deprecation and use the class available on older SDK
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"CityBoard"
                                                        message:error.errorDescription
                                                       delegate:self
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil];
        [alert show];
#pragma clang diagnostic pop
zveljkovic
  • 444
  • 4
  • 16
1

Swift 2.0:

Use AlertController.

Example for Action Sheet:

  let mediaActionSheet: UIAlertController = UIAlertController(title: "Media Action Sheet", message: "Choose an option!", preferredStyle: .ActionSheet)

  //Create and add the Cancel action
  let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .Cancel) { action -> Void in

   //Just dismiss the action sheet

  }
  mediaActionSheet.addAction(cancelAction)
  //Create and add first option action
  let takePictureAction: UIAlertAction = UIAlertAction(title: "Take Picture", style: .Default) { action -> Void in

   //Code for launching the camera goes here

  }

  mediaActionSheet.addAction(takePictureAction)

  //Create and add a second option action
  let choosePictureAction: UIAlertAction = UIAlertAction(title: "Choose From Gallery", style: .Default) { action -> Void in

   //Code for picking from gallery goes here

  }

  mediaActionSheet.addAction(choosePictureAction)

  //Present the AlertController
  self.presentViewController(mediaActionSheet, animated: true, completion: nil)

Example for Alerts:

1)

let simpleAlert = UIAlertController(title: "Simple Alert", message: "It is just awesome", preferredStyle: UIAlertControllerStyle.Alert);

  //show it
  showViewController(simpleAlert, sender: self);

2) Alert With TextField in it.

  let inputTextFieldAlert:UIAlertController = UIAlertController(title: " Input TextField Alert ", message: " Enter on the below TextField ", preferredStyle: UIAlertControllerStyle.Alert);

  //default input textField (no configuration...)
  inputTextFieldAlert.addTextFieldWithConfigurationHandler(nil);

  //no event handler (just close dialog box)
  inputTextFieldAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.Cancel, handler: nil));

  //event handler with closure
  inputTextFieldAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default, handler: {(action:UIAlertAction) in

   let fields = inputTextFieldAlert.textFields!;
   print("Output: "+fields[0].text!);
  }));

  presentViewController(inputTextFieldAlert, animated: true, completion: nil);

3)

var alert = UIAlertController(title: "TextField Alert", message: "Enter on the below TextField", preferredStyle: UIAlertControllerStyle.Alert);

  //configured input textField
  var field:UITextField?;

  alert.addTextFieldWithConfigurationHandler({(input:UITextField)in
   input.placeholder="Empty Dtaa ;-)";
   input.clearButtonMode=UITextFieldViewMode.WhileEditing;

   field=input;
  });

  //YES Handler
  func yesHandler(actionTarget: UIAlertAction){

   print(field!.text!);
  }
  //event handler with predefined function
  alert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default, handler: yesHandler));

  presentViewController(alert, animated: true, completion: nil);
Alvin George
  • 14,148
  • 92
  • 64
  • what if you wanted to do this: let simpleAlert = UIAlertController(title: "Simple Alert", message: "You selected row %ld from list", preferredStyle: UIAlertControllerStyle.Alert); where you want to replace %ld with the value? – Famic Tech Aug 14 '16 at 15:29
0

The examples above didn't help me much. My solution is for XCode 6.4., Swift 1.2 and you can copy and paste this code in a test project to get a feeling how it works :

SOLUTION 1 - Swift 1.2 :

import UIKit

let ALERT_TITLE   = "Got you working, right?"
let ALERT_MESSAGE = "Well maybe..."

class ViewController: UIViewController
{
    private var alert: UIAlertController!

    private var presentAlertButton: UIButton!

    override func viewDidAppear(animated: Bool)
    {
        /*
        // QUICK TEST - 1
        self.presentViewController(alert, animated: true, completion: nil)
        */


        // QUCIK TEST - 2
        /*
        let rootVC = UIApplication.sharedApplication().keyWindow?.rootViewController
        rootVC?.presentViewController(alert, animated: true, completion: nil)
        */
    }

    override func viewDidLoad()
    {
        super.viewDidLoad()

        createAndAddAlertV()

        createAndAddAlertButton()
    }

    private func createAndAddAlertV()
    {
        alert = UIAlertController(title:ALERT_TITLE, message:ALERT_MESSAGE, preferredStyle: .Alert)
        let alertAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
        alert.addAction(alertAction)
    }

    private func createAndAddAlertButton()
    {
        presentAlertButton = UIButton(frame: CGRectMake(
            view.frame.size.width / 2,
            view.frame.size.height / 2,
            200,
            100))

        presentAlertButton.layer.anchorPoint = CGPointMake(1.0, 1.0)
        presentAlertButton.backgroundColor = UIColor.redColor()
        presentAlertButton.setTitle("Click For Alert", forState: .Normal)
        presentAlertButton.addTarget(self, action: "showAlertV", forControlEvents: .TouchUpInside)
        self.view.addSubview(presentAlertButton)
    }

    @IBAction func showAlertV()
    {
        println(" Showing... ")
        self.presentViewController(alert, animated: true, completion: nil)
    }

}

I checked this solution in Xcode 7.0. It worked. Xcode made one change. I recompiled it in Xcode 6.4 again and it worked. The changes for Swift 2.0 should be minor if existent at all.

Hope this helps ;)

MB_iOSDeveloper
  • 4,178
  • 4
  • 24
  • 36
0

You can use this code for Alert view :

 UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"Message" preferredStyle:UIAlertControllerStyleAlert];

        UIAlertAction* ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
        [alertController addAction:ok];

        [self presentViewController:alertController animated:YES completion:nil];

For multiple buttons you can use :

 UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"Message" preferredStyle:UIAlertControllerStyleAlert];

        [alertController addAction:[UIAlertAction actionWithTitle:@"Button 1" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            [self loadGooglrDrive];
        }]];

        [alertController addAction:[UIAlertAction actionWithTitle:@"Button 2" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            [self loadDropBox];
        }]];

        [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            [self closeAlertview];
        }]];

        dispatch_async(dispatch_get_main_queue(), ^ {
            [self presentViewController:alertController animated:YES completion:nil];
        });

-(void)closeAlertview
{

    [self dismissViewControllerAnimated:YES completion:nil];
}
Nithinbemitk
  • 2,710
  • 4
  • 24
  • 27
0

https://github.com/nagibazad/UIAlertControllerWrapper

This wrapper provides a way of converting UIAlertView to UIAlertController easily. UIAlertView is deprecated from iOS 9.0. Convert your UIAlertView of old projects to UIAlertController keeping your delegate implementation remain same using this UIAlertControllerWrapper and get rid of all the UIAlertView related warnings.

Torongo
  • 1,021
  • 1
  • 7
  • 14