UIAlertView deprecated in iOS9 – our workaround

MyAlertView

When moving an objective-c application to iOS 9 you will have to deal with the depreciation of UIAlertView.  If your apps have few uses of AlertView this is a small problem and manually replacing your UIAlertView code with UIAlertController is the way to go.

When we started the move of BeamWriter to iOS 9 however, xCode gave us close to 200 ‘UIAlertView id deprecated, use UIAlertController instead’ warnings, and we did not have the patience to re-write all that code manually.

Luckily most of our uses of UIAlertView were pretty basic  –  usually only the single dismiss button, and only occasionally with other buttons requiring a delegate.  We therefore decided to write a ‘wrap’ for UIAlertController which would allow us to rename our calls to UIAlertView, keep the old delegate callbacks and be good.   Here is what we did:

Create a new Class ‘MyAlertView’ with header MyAlertView.h:

#import <UIKit/UIKit.h>

@class MyAlertView;

@protocol MyAlertViewDelegate <NSObject>

@optional

-(void)alertView:(MyAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;

@end

@interface MyAlertView : UIViewController

/**
Holds the alert controller actually used to display the alert.
*/
@property UIAlertController *myAlertController;

/**
    The delegate if one specified. This will be called with the button pressed

*/
@property id<MyAlertViewDelegate> delegate;


-(id)initWithTitle: (NSString *)title message: (NSString *)message delegate: (id<MyAlertViewDelegate>) delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles: (NSString *) otherButtonTitle, ...;


-(void)show: (UIViewController *)v ;

@end

With Implementation MyAlertView.m:

#import "MyAlertView.h"
#import "stdio.h"

@implementation MyAlertView

-(id)initWithTitle: (NSString *)title message: (NSString *)message delegate: (id<MyAlertViewDelegate>) delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles: (NSString *) otherButtonTitle, ...
{
    self=[super init];

    if (self) {

        [self setMyAlertController:[UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]];

        UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:cancelButtonTitle style:UIAlertActionStyleDefault

                                                              handler:^(UIAlertAction * action) { [self clicked:0]; }];

        [[self myAlertController] addAction:defaultAction];

        // Add buttons for button number two .. n if present.

        int count = 0;
        va_list ap;
        va_start(ap, otherButtonTitle);
        id object = otherButtonTitle;
        while (object) {           

            // Create a button with the argument

            defaultAction = [UIAlertAction actionWithTitle:(NSString *)object style:UIAlertActionStyleDefault

                                                   handler:^(UIAlertAction * action) { [self clicked:(NSInteger)count + 1]; }];

            [[self myAlertController] addAction:defaultAction];
            ++count;
            object = va_arg(ap, id);

        }

        va_end(ap);

        // set the delegate
        [self setDelegate:delegate];
    }

    return self;

}

-(void)show: (UIViewController *)v
{

    [v presentViewController:[self myAlertController] animated:YES completion:nil];

}


/**
 Method to call when a button is clicked. If the delegate is set, the delegate's alertView:(MyAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;

 is called with the index of the button. If the delegate is not set, nothing is done.
 */

-(void)clicked:(NSInteger)i
{

    if ([self delegate]) {

        [[self delegate] alertView:self clickedButtonAtIndex:i];

    }
}

@end

Finally you need to:

  1. Include MyAlertView.h in the files where you currently use UIAlertView.
  2. Add ‘MyAlertViewDelegate’ to the list of delegates of any class where you currently have ‘UIAlertViewDelegate’  (yes – search/replace…)
  3. Replace all references to ‘UIAlertView’ with ‘MyAlertView’
  4. Replace the calls you currently have to [‘yourUIAlertView’ show] – i.e the code that with UIAlertView causes the alert to be shown – with [‘yourMyAlertView show:self] OR [‘yourMyAlertView show:’any UIViewController’].  UIAlertController which is actually used to show the alert needs to be called FROM a UIViewController that is in the controller hierarchy (this is the big change). It was previously possible to present alerts from non-view controllers. That is no longer the case.

That’s it.  This small ‘wrap around’ saved us many hours of tedious re-coding.