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 UIAlertView
s, 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.
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.
Unfortunately as far as I understand it, no you cannot effectively create anonymous inner classes. The syntax you suggest would be really nice IMO though.
Here is my attempt at getting something close to what you want, it's no where near as clean though.
import UIKit
class AlertViewDelegate: NSObject, UIAlertViewDelegate {
func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int) {
}
func alertView(alertView: UIAlertView!, didDismissWithButtonIndex buttonIndex: Int) {
}
func alertView(alertView: UIAlertView!, willDismissWithButtonIndex buttonIndex: Int) {
}
func alertViewCancel(alertView: UIAlertView!) {
}
func alertViewShouldEnableFirstOtherButton(alertView: UIAlertView!) -> Bool {
return true
}
}
class ViewController: UIViewController {
var confirmDelegate: AlertViewDelegate?
func doSoemthing() {
confirmDelegate = {
class ConfirmDelegate: AlertViewDelegate {
override func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int) {
println("clicked button \(buttonIndex)")
}
}
return ConfirmDelegate()
}()
let alertView = UIAlertView(title: "Test", message: "OK", delegate: confirmDelegate, cancelButtonTitle: "Cancel")
}
}