Simplify Your UIAlertController Creation with @resultBuilder in Swift

Daniil Vereshchagin
3 min readJun 23, 2024

--

ResultBuilder in Swift

Ever wished you could make your UIAlertController setup cleaner and more intuitive? Enter @resultBuilder, a powerful feature in Swift that can help you create domain-specific languages (DSLs) within Swift, making your code more readable and maintainable.

In this article, i will explore how to use @resultBuilder to streamline the creation of UIAlertController. This is reallife case, when i use in my applications.

By the end of this guide, you'll be able to create alert controllers with multiple actions in a more modular and organized way.

What is @resultBuilder?

@resultBuilder (formerly known as @functionBuilder) is an attribute in Swift that enables you to create DSLs. It allows you to build complex structures using a clean and declarative syntax, similar to SwiftUI.

Let’s dive into an example where we use @resultBuilder to simplify the creation of UIAlertController:

Step 1: Define the Structure for UIAlertAction

First, i will create a structure to represent an alert action:

import UIKit

struct AlertAction {
let title: String
let style: UIAlertAction.Style
let handler: ((UIAlertAction) -> Void)?
}

Step 2: Define the @resultBuilder

Next, i will define our @resultBuilder, which will aggregate alert actions into an array:

@resultBuilder
struct AlertBuilder {
static func buildBlock(_ components: AlertAction...) -> [AlertAction] {
return components
}
}

Step 3: Extend UIAlertController to Use @resultBuilder

I then extend UIAlertController to accept our @AlertBuilder:

extension UIAlertController {
convenience init(
title: String?, message: String?,
preferredStyle: UIAlertController.Style,
@AlertBuilder actions: () -> [AlertAction]
) {
self.init(title: title, message: message, preferredStyle: preferredStyle)
let builtActions = actions()
for action in builtActions {
let alertAction = UIAlertAction(title: action.title, style: action.style, handler: action.handler)
self.addAction(alertAction)
}
}
}

Step 4: Create a Helper Function for AlertAction

To make it easier to create AlertAction objects, we'll define a helper function:

func AlertAction(
title: String,
style: UIAlertAction.Style = .default,
handler: ((UIAlertAction) -> Void)? = nil
) -> AlertAction {
return AlertAction(title: title, style: style, handler: handler)
}

Step 5: Use the DSL to Create a UIAlertController

Finally, we use our DSL to create a UIAlertController:

func showAlert(on viewController: UIViewController) {
let alert = UIAlertController(title: "Title", message: "Message", preferredStyle: .alert) {
AlertAction(title: "OK") { _ in
print("OK tapped")
}
AlertAction(title: "Cancel", style: .cancel) { _ in
print("Cancel tapped")
}
AlertAction(title: "Destructive", style: .destructive) { _ in
print("Destructive tapped")
}
}

viewController.present(alert, animated: true, completion: nil)
}

Explanation

  1. AlertAction: A structure representing an alert action, containing the title, style, and handler.
  2. AlertBuilder: A @resultBuilder that aggregates actions into an array.
  3. UIAlertController Extension: Adds a convenient initializer that takes @AlertBuilder and creates actions based on the provided data.
  4. AlertAction Function: Simplifies the creation of AlertAction objects.
  5. Using the DSL: Creates a UIAlertController using the new DSL syntax, adding actions in a cleaner and more intuitive way.

Conclusion

This example demonstrates how @resultBuilder can be utilized to create a DSL that simplifies the creation process of UIAlertController with multiple actions. This approach makes the code more readable and easier to maintain, especially when you need to add several actions to an alert.

By leveraging @resultBuilder, you can make your UIAlertController setup more modular and organized, improving both development speed and code quality.

Try it out in your next project and see how much cleaner and more maintainable your code can be!

--

--