Pass selector (function name) to function in swift

Works for a Living picture Works for a Living · Aug 19, 2016 · Viewed 8k times · Source

I want to pass the selector for a function to another function. Right now I'm just passing the string and doing several if statements. If I could pass the actual function selector to the function, I could eliminate all the if statements.

My current function:

func getBtn(i: String, f: String) -> UIBarButtonItem
{
    let btn: UIButton = UIButton();
    btn.frame=CGRectMake(0,0,30,30)
    btn.setBackgroundImage(UIImage(named:i), forState: UIControlState.Normal)
    if f == "funcOne"{ btn.addTarget(self, action: #selector(self.funcOne), forControlEvents:.TouchUpInside) }
    else if f == "funcTwo"{ btn.addTarget(self, action: #selector(self.funcTwo), forControlEvents:.TouchUpInside) }
    else if f == "funcThree"{ btn.addTarget(self, action: #selector(self.funcThree), forControlEvents:.TouchUpInside) }
    else if f == "funcFour"{ btn.addTarget(self, action: #selector(self.funcFour), forControlEvents:.TouchUpInside) }
    // etc.
    let barBtn = UIBarButtonItem(customView: btn)
    return barBtn;
}

Usage:

items.append(self.getBtn("checkmark",f:"funcOne"));

What I'd like to be able to do:

func getBtn(i: String, f: SOME_TYPE_OF_THING) -> UIBarButtonItem
{
    let btn: UIButton = UIButton();
    btn.frame=CGRectMake(0,0,30,30)
    btn.setBackgroundImage(UIImage(named:i), forState: UIControlState.Normal)
    btn.addTarget(self, action: #selector(f), forControlEvents:.TouchUpInside)
    let barBtn = UIBarButtonItem(customView: btn)
    return barBtn;
}

Usage:

items.append(self.getBtn("checkmark",f:self.funcOne));

Answer

matt picture matt · Aug 19, 2016

The purpose of #selector() syntax is to save you from the possible error in having to write a selector as a literal string, which is error-prone. Nevertheless, you are free to write Selector(f) instead of using #selector() syntax.

However, it would be even better if f were itself typed as Selector:

func getBtn(i: String, f: Selector) -> UIBarButtonItem

That way, you could keep using #selector but do it in the call:

items.append(self.getBtn("checkmark",f:#selector(funcOne)))

In getBtn you would then just pass f directly as the button action.