iosswiftuialertviewanonymous-inner-classuialertviewdelegate

Can you create anonymous inner classes in Swift?


I'm tired of declaring entire classes as having the ability to handle UIAlertView clicks by making them extend UIAlertViewDelegate. It starts to feel messy and wrong when I have multiple possible UIAlertViews, and have to distinguish which was clicked in the handler.

What I really want is to create a single object that implements the UIAlertViewDelegate protocol, and give this one-off object to my UIAlertView when showing it.

I want something like this:

let confirmDelegate = UIAlertViewDelegate() {
    func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int) {
        // Handle the click for my alertView
    }
}

And then use it when showing the alert:

let alertView = UIAlertView(title: "Confirm", message: "Are you sure?", delegate: confirmDelegate, cancelButtonTitle: "No", otherButtonTitles: "Yes")
alertView.show()

Is this possible without declaring a new class?

I understand I could do something like this:

class ConfirmDelegate: UIAlertViewDelegate {
    func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int) {
        // ...
    }
}

And then instantiate a ConfirmDelegate(), but I'm just wondering if this is possible as one-liner class declaration and instantiation.


Solution

  • As @ChrisWagner states in his comment, you shouldn't need to do any of this in iOS8, at least for UIAlertView since there is a new UIAlertViewController that uses closures without any delegates. But from an academic point of view, this pattern is still interesting.

    I wouldn't use anonymous class at all. I would just create a class that can be assigned as the delegate and accept closures to execute when something happens.

    You could even upgrade this to accept a closure for each kind of action: onDismiss, onCancel, etc. Or you could even make this class spawn the alert view, setting itself as the delegate.

    import UIKit
    
    class AlertViewHandler: NSObject, UIAlertViewDelegate {
        typealias ButtonCallback = (buttonIndex: Int)->()
        var onClick: ButtonCallback?
    
        init(onClick: ButtonCallback?) {
            super.init()
            self.onClick = onClick
        }
    
        func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int) {
            onClick?(buttonIndex: buttonIndex)
        }
    }
    
    
    class ViewController: UIViewController {
    
        // apparently, UIAlertView does NOT retain it's delegate.
        // So we have to keep it around with this instance var
        // It'll be nice when all of UIKit is properly Swift-ified :(
        var alertHandler: AlertViewHandler?
    
        func doSoemthing() {
            alertHandler = AlertViewHandler({ (clickedIndex: Int) in
                println("clicked button \(clickedIndex)")
            })
    
            let alertView = UIAlertView(
                title: "Test",
                message: "OK",
                delegate: alertHandler!,
                cancelButtonTitle: "Cancel"
            )
        }
    }
    

    Passing around closures should alleviate the need for anonymous classes. At least for the most common cases.