AndyIbanez / andyibanez-com

Static website.
1 stars 0 forks source link

posts/understanding-function-builders/ #10

Open utterances-bot opened 4 years ago

utterances-bot commented 4 years ago

Understanding Function Builders in Swift • Andy Ibanez

https://www.andyibanez.com/posts/understanding-function-builders/

pavm035 commented 4 years ago

Very nice article :) BTW I think it can be further simplified by

Actions

typealias RAlertActionHandler = () -> Void

protocol RAlertAction {
    var title: String { get }
    var style: UIAlertAction.Style { get }
    var action: RAlertActionHandler { get }
}

struct DefaultAction: RAlertAction {
    let title: String
    let style: UIAlertAction.Style
    let action: RAlertActionHandler

    init(_ title: String, action: @escaping RAlertActionHandler = {}) {
        self.title = title
        self.style = .default
        self.action = action
    }
}

struct CancelAction: RAlertAction {
    let title: String
    let style: UIAlertAction.Style
    let action: RAlertActionHandler

    init(_ title: String, action: @escaping RAlertActionHandler = {}) {
        self.title = title
        self.style = .cancel
        self.action = action
    }
}

struct DestructiveAction: RAlertAction {
    let title: String
    let style: UIAlertAction.Style
    let action: RAlertActionHandler

    init(_ title: String, action: @escaping RAlertActionHandler = {}) {
        self.title = title
        self.style = .destructive
        self.action = action
    }
}

Then function builder by

@_functionBuilder
struct RAlertControllerBuilder {
    static func buildBlock(_ components: RAlertAction...) -> [UIAlertAction] {
        components.map { action in
            UIAlertAction(title: action.title, style: action.style) { _ in
                action.action()
            }
        }
    }
}

// MARK:- UIAlertController
extension UIAlertController {
    convenience init(title: String,
                     message: String,
                     style: UIAlertController.Style = .alert,
                     @RAlertControllerBuilder build: () -> [UIAlertAction]) {
        let actions = build()
        self.init(title: title, message: message, preferredStyle: style)
        actions.forEach { self.addAction($0) }
    }
}

Finally alert controller

let alert = UIAlertController(
            title: "Delete all data?",
            message: "All your data will be deleted!") {
                DestructiveAction("Yes, Delete it All") {
                    print("Deleting all data")
                }

                DefaultAction("Show More Options") {
                    print("showing more options")
                }

                CancelAction("No, Don't Delete Anything")
        }

        present(alert, animated: true)