---
title: "UIAlertController For iOS 7 Or When One Might Use Associated References"
description: "Today I want to share with you one of my pieces of code that has proved to be quite useful. Sometimes what you need is not something brilliant or especially sophisticated, but something steady and dependable, doing all that annoying work for you. Well that’s DAAlertController."
url: https://manytomany.co/blog/uialertcontroller-for-ios-7-or-when-one-might-use-associated-references/
published: 2015-03-09
---

# UIAlertController For iOS 7 Or When One Might Use Associated References

9 March 2015 · Daria Kopaliani

This is an archived article from the website of Factorial Complexity Ltd., an older incarnation of many-to-many. Information may be outdated or inaccurate.

Today I want to share with you one of my pieces of code that has proved to be quite useful. Sometimes what you need is not something brilliant or especially sophisticated, but something steady and dependable, doing all that annoying work for you. Well that’s `DAAlertController`.

I did not think that I would be ever so happy to learn that a certain cocoa API got deprecated. But let’s hand it to `UIAlertView` and `UIActionSheet` - they were always different and not “good different”. I could not have said it better than Matt:

> “From its very inception, UIAlertView has been laden with vulgar concessions, sacrificing formality and correctness for the whims of an eager developer audience”.

Fortunately the new `UIAlertController` is everything that `UIAlertView` was not. First of all, a subclass of `UIViewController`, then it has these beautiful long objective-c style methods allowing the user to specify actions (buttons) at any time (constructor dependency injections were never meant for methods with variable length parameters, right?), and finally completion handlers always win over delegates these days.

And even though it preserved some of `UIAlertView`’s ”blackbox”-ness, `UIAlertController` does a much better job handling edge cases. Have you ever tried to have 10 buttons in `UIAlertView`? Yes, I know, alert is not the best “choice” for that multi-choice scenario, but if the API allows you to specify that many buttons, it should either handle them nicely or fail gracefully. Well, unlike it’s predecessor, `UIAlertController` will put buttons on a scroll view and will not sacrifice the title.

So if you are a luckier developer and only target iOS 8+ devices, enjoy the new API, otherwise check `DAAlertController` out, it’s a real timesaver.

When you have to support both iOS 8 and 7 and use alert views or actions sheets in your projects, you usually end up with a large `if` / `else` statement. Code inside `if (NSStringFromClass([UIAlertController class])) { ... }` is usually quite neat due to the block based API, while `else { ... }` can turn into a real nightmare and often will make your class implement a `UIAlertViewDelegate` and/or `UIActionSheetDelegate` protocols. So when you finally decide to drop iOS7 support, getting rid of old alert views will not be that easy.
If only there was a way to use completion handlers for old `UIAlertView`s and `UIActionSheet`s… Well that’s exactly what `DAAlertController` does - it incapsulates these large if/else statements and has a nice `UIAlertController`\-like API for both iOS 8 and 7.

Let’s take a look at the case of a simple alert view:

```objc
DAAlertAction *cancelAction = [DAAlertAction actionWithTitle:@"Cancel"
    style:DAAlertActionStyleCancel handler:nil];

DAAlertAction *signOutAction = [DAAlertAction actionWithTitle:@"Sign out"
    style:DAAlertActionStyleDestructive handler:^{
        // perform sign out
    }];

[DAAlertController showAlertViewInViewController:self
    withTitle:@"Are you sure you want to sign out?"
    message:@"If you sign out of your account all photos will be removed from this iphone."
    actions:@[cancelAction, signOutAction]];
```

Here is what you will get for iOS 8 and 7: (`UIAlertView` does not support destructive buttons so “Sign out” button will be rendered as a default button)

If `UIAlertContoller` is available `DAAlertController` will just pass all the work to it, otherwise it will use associated references (explained in detail later) to invoke action handlers when buttons are clicked just like `UIAlertController` would.

Naturally, `DAAlertController` is limited to what the old `UIAlertView` and `UIActionSheet` could do: - action sheets can only have one destructive button (buttons for other destructive actions will be rendered as default buttons) - alert views cannot have any destructive buttons (again, all buttons will look like default buttons) - alert views can only have up to 2 text fields - action sheets can only have a title; a message will not be displayed - you can only specify up to 10 actions for iOS 7 (otherwise alert views / action sheets would not be rendered properly anyways)

There is also one bonus: one thing that `DAAlertController` does better than `UIAlertController` is autoenabling buttons based on the contents of textfield(s). In the old API there was just one convenient delegate method `alertViewShouldEnableFirstOtherButton`; now with `UIAlertController` it’s a whole big deal - you need to subscribe to `UITextFieldTextDidChangeNotification` in text field configuration blocks and remember to unsubscribe when necessary, which is possible in any of the action’s handlers, so it really gets messy. So here is what you would do with `DAAlertController` in the following use case: imagine you want to present a sign up dialog, “full name” is optional, but “nickname” is required and should be at least 5 characters long:

```objc
DAAlertAction *cancelAction = [DAAlertAction actionWithTitle:@"Cancel"
    style:DAAlertActionStyleCancel
    handler:nil];

DAAlertAction *signUpAction = [DAAlertAction actionWithTitle:@"Sign up"
    style:DAAlertActionStyleDefault handler:^{
        // perform sign up
    }];

[DAAlertController showAlertViewInViewController:self
    withTitle:@"Sign up"
    message:@"Please choose a nick name."
    actions:@[cancelAction, signUpAction]
    numberOfTextFields:2
    textFieldsConfigurationHandler:^(NSArray *textFields)
    {
        UITextField *nickNameTextField = [textFields firstObject];
        nickNameTextField.placeholder = @"Nick name";
        UITextField *fullNameTextField = [textFields lastObject];
        fullNameTextField.placeholder = @"Full name";
    } validationBlock:^BOOL(NSArray *textFields) {
        UITextField *nickNameTextField = [textFields firstObject];
        return nickNameTextField.text.length >= 5;
    }];
```

This little snippet will do it for both iOS 7 and 8 and it’s 6 times less code than you’d have using `UIAlertController` API.

Methods for presenting action sheets are quite similar, but they also include parameters for `sourceView` or `barButttonItem` and `permittedArrowDirections`.

So that’s it for you guys looking for a simple Util to make `UIAlertController` work for iOS 7 (in a way), go grab a [pod](http://cocoapods.org/?q=DAAlertController) or fork a [github repo](https://github.com/daria-kopaliani/DAAlertController). For those of you interested in my struggle with `UIAlertView` and how associated references were a help, here is my story:

As you probably noticed, `DAAlertController` takes an array of `DAAlertActions` as a parameter; the challenge is to transform that array into a “nil terminated” `otherButtonTitles` to pass into a `UIAlertView` designated initialiser `initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:` You might wonder why don’t just pass `nil`as `otherButtonTitles` and configure them later (using `addButtonWithTitle:` method). This is exactly what I did at first and was the reason for the first bug report to apple. It turns out that if you do pass `nil` as `otherButtonTitles` and regardless of whether you specify them later, `firstOtherButtonIndex` will always remain `-1`. And this results in `alertViewShouldEnableFirstOtherButton` never being called, which is something we cannot afford if we want to disable buttons when there is no text in alert view’s textfiled(s). This gives us no choice other than to specify other button titles in the initialiser method.
So back to the problem of turning an `NSArray` into a variable argument list. Well, if you know of a way to do that in an `ARC` environment, please get in touch with me, and I will buy you a beer. (“Cocoa is my girlfriend” has a solution for a non-ARC case). Anyways, variadic methods is something I no longer want to get involved with. Who knows how they are doing the “shifting” (variable argument lists have no introspection), especially at a time when extra 32bits can always hide around the corner. So I decided to fight variable argument lists with their own essence - being nil terminated:

```objc
NSArray *otherButtonTitles = @[...];

...otherButtonTitles:(otherButtonTitles.count > 0) ? otherButtonTitles[0] : nil,
(otherButtonTitles.count > 1) ? otherButtonTitles[1] : nil,
(otherButtonTitles.count > 2) ? otherButtonTitles[2] : nil,
(otherButtonTitles.count > 3) ? otherButtonTitles[3] : nil, 
... ,nil];
```

Not the prettiest code I’ve ever written, but it does the trick and will work for any architecture.
I only check for 10 buttons, because if you need more, you should really consider using a custom popover instead of `UIAlertView`.

So we managed to specify titles for buttons; now we want to trigger action handlers when they are “clicked.” The `UIAlertViewDelegate` only notifies us about the index of a button clicked. Here usage of associated references seemed totally justified for me (for once!) so I went for it. First you want to include, then do the actual “association” :

```objc
objc_setAssociatedObject(alertView, @“otherActions", otherActions, OBJC_ASSOCIATION_COPY);
```

and later, when the button is clicked, you’ll be able to access `otherActions` of the given alertView

```objc
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex != alertView.cancelButtonIndex) {
        NSArray *otherActions = objc_getAssociatedObject(alertView, @"otherActions");
        DAAlertAction *selectedAction = otherActions[buttonIndex - alertView.firstOtherButtonIndex];
        if (selectedAction.handler) {
            selectedAction.handler();
        }
    }

    // ...
}
```

One more thing to notice is that objects being “associated” need to implement `<NSCopying>` protocol.

There are more weird `UIAlertController`/`UIActionSheet` issues (like tuning `UIAlertViewStyleLoginAndPasswordInput`textfield to serve our needs, fighting with `UIActionSheet` not to show cancel button on iPad in some cases, etc) dealt with in `DAAlertController.m`, you can find more details in comments there. I just hope that soon cocoa will not leave us any excuse to use associated references whatsoever.

Please enjoy and fork!

![Vitalii](https://manytomany.co/vitalii-yellow.png)

## Hi. I'm Vitalii.

I’m a software developer, technical manager and solo entrepreneur. I have been building software products all my life. I am offering **CTO as a Service** at many-to-many.

## Contact me

Let me know what are you looking for. I will reach out to you via the provided email with quote and follow up questions. Alternatively, [book a call](https://calendly.com/many-to-many/intro) or reach me directy by email [hello@manytomany.co](mailto:hello@manytomany.co).

Or using your preferred messaging app:

 [![WhatsApp QR Code](https://manytomany.co/qr/qr-whatsapp.png)](https://wa.me/qr/QH6GQNCO5CZEO1)[WhatsApp](https://wa.me/qr/QH6GQNCO5CZEO1)

 [![Telegram QR Code](https://manytomany.co/qr/qr-telegram.png)](https://t.me/wicharek)[Telegram](https://t.me/wicharek)
