From the blog

Raisin Toast – A Custom UIAlertView for iOS

Animated GIF of the Raisin Toast sample project in action.Simple, themed, app wide messaging layer for presenting errors, info and feedback to users.

You got your screen comps from the designer, you fired up Xcode and it’s the last day of the sprint. The screen you built is pixel perfect to the design, and the unit tests are passing, but you just got a new error from the API that you need to communicate to the user about the data they provided.

Fear not! The sprint isn’t a bust. What are your options?

There are five commonly adopted solutions to this kind of messaging layer, each with its own benefits and drawbacks. Let’s take a look at them and then introduce Raisin Toast.

Do nothing

You’re short on time. Tempted to skip handling the error? It’s a fast but lazy approach, it’s bad form and you’ll lose the respect of any developers who have to maintain your code. At least throw a comment in if you know it’s safe to ignore the error.

UIAlertView

This old standby is well known, easy to implement, allows you to interact with the user to give them a choice about what happens next and offers consistent UI if used throughout the app. UIAlertViews are modal so they don’t interfere with the view hierarchy, locking off interactions with the underlying view controller, which can be a good thing.

On the downside they are pretty ugly with very few formatting options and no images, so if you’re looking for messaging to match your brand you’re out of luck. The modal nature of these alerts can also be pretty jarring to users since it interrupts their flow. UIAlertView gives delegate callbacks for user responses, but uses confusing button indexing to determine which option the user chose. Alternatively, you can use something like UIAlertView+RZCompletionBlocks – a category available in RZUtils that uses completion blocks instead of delegation.

Most importantly, UIAlertView is deprecated as of iOS 8.

If you’re in a bind, an alert view is a good stop gap but chances are you’ll be revisiting this code once your product manager starts testing the app.

UIActionSheet

UIActionSheet extends the capabilities of UIAlertView by allowing you to construct the available options after the initializer, adding flexibility. UIActionSheet is also a better choice over UIAlertView when there is a destructive action.

However, presentation is limited to the bottom of the screen on the iPhone and, like UIAlertView, it is deprecated in iOS 8.

UIAlertController

UIAlertController is the iOS 8 counterpart to UIAlertView and UIActionSheet. It combines the capabilities of both, adds a saucy background blur and gives more control over style.

UIAlertController is presented with presentViewController:animated:completion: so you get the benefit of completion blocks instead of delegation.

Underneath it all, you’ve still got a UI element that looks jarring relative to the rest of your app and feels very much like an interruption. In the context of the last minute API error it’s not a great choice.

Custom view

Adding a custom view gives you complete UI and formatting control, image support and partial screen or modal presentation. You can add actionable elements if you need them and create your own delegate protocol or use blocks.

Great! You whip up the UI in interface builder, update your view controller to present and dismiss the view (or create a view controller to contain it), test on a handful of devices and before you know it, you’re working late into the night trying to wrap it up for sprint review in the morning.

It all needs to be tested, you might need some graphics from the designer who already left for the day and now your view controller has another 200 lines of code. Does it look like the rest of the app? Could you refactor it to use elsewhere in the app?

What seems like the ideal option frequently results in lots more work polishing your code.

Custom View Controller

Another custom approach would be a custom view controller. It has many of the same benefits of a custom view and the added benefit of being more readily designed for reuse elsewhere in the app. It’s easier to present and dismiss than a custom view.

It also has the same drawback but adds the constraint in many view hierarchies of being presented modally.

Custom view controllers generally are not suitable last minute additions to your code. Even planning to use a custom view controller for this type of messaging from the start feels like reinventing the wheel.

How do you get the simplicity and appwide look of UIAlertView with the power of custom views and custom view controllers? Something that is just as easy and lightweight to add to your view controllers as a UIAlertView.

Enter Raisin Toast

Borrowing its name from Android Toast, Raisin Toast allows you to quickly present the user with an attractive, customizable messaging layer.

The initial configuration typically lives in the app delegate where a default messaging UIWindow is added:

A single line of code in your view controller presents the message to the user:

What does it look like?

Animated GIF of the Raisin Toast sample project in action.
Raisin Toast sample project in action.

Beyond the out of the box styles you can customize colors easily and create a custom messaging view controller for further customization including actionable elements, form-fields etc.,

Basically it offers everything a custom view controller can provide but used consistently throughout the app. It also offers support for multiple active messaging styles/themes.

It’s a great choice to incorporate right at the start of a project because it makes all your messaging predictable and limits mistakes to typos in the text you provide.

Adding a second UIWindow to the app might put some users off but Raisin Toast mitigates the most common issues multiple UIWindows introduce of handling rotation and passthrough gesture handling.

About that sprint – with Raisin Toast you can handle the API error gracefully, providing an attractive messaging window in less than 10 minutes and commit your code on time.

Conclusion

Always try to keep your users informed about what’s going on so the app doesn’t look like it’s just not working. Your users will reward you with better or fewer support requests (and maybe better reviews).

It’s painless with Raisin Toast: everything else is just enough work or looks too rough to make it easy to do so the default is often to skip the messaging.

Instead of spending a day or two developing and testing a reusable messaging view controller, spend a few hours creating a custom app themed view controller implementing the RZMessagingViewController protocol so you can use it with Raisin Toast for the same great custom appearance with a fraction of the custom code.

It’s everything you wished for if you could create a custom UIAlertView.

Raisin Toast is open source and can be found at GitHub and is also available as a CocoaPod with a sample project you can try.

Interested in joining the Raizlabs team making great software? We’re hiring in Boston and SF.

5 Comments

  1. Bad link there on “UIAlertView+RZCompletionBlocks”, I think you added an extra square bracket where there shouldn’t have been one.

  2. Hi Adam, thanks for posting this it looks awesome!

    One question, I’ve installed the podfile into my project and follwed the guidance on GitHug but whenever I call:

    [RZErrorMessenger displayErrorWithTitle:@”FYI” detail:@”This is a test of the emergency broadcast system”];

    I get this error message:

    You must call setDefaultMessagingWindow with a valid RZMessagingWindow to display an error, typically in your app delegate when you configure the RZMessagingWindow view creation, configuration, preesntation and dismissal blocks.

    Any advice would be appreciated.

    Thanks

  3. Hi Tim,
    Thanks for trying it out!

    It looks as though you’re not configuring the defaultMessagingWindow in the app delegate. From the configuration section of the readme.md :

    -(void)applicationDidBecomeActive:(UIApplication *)application
    {
    [self.window makeKeyAndVisible]; // Must come first

    [RZErrorMessenger setDefaultMessagingWindow:[RZMessagingWindow defaultMessagingWindow]];
    }

    If you’re still having trouble ping me at [email protected]

Leave a Reply

Your email address will not be published. Required fields are marked *