Pass selector (function name) to function in swift
Asked Answered
L

2

15

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));
Lebbie answered 19/8, 2016 at 16:41 Comment(0)
S
28

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.

Supersensitive answered 19/8, 2016 at 16:44 Comment(3)
Thanks for nailing that. I'm getting no errors. Exactly what I was hoping for. Will test now in a build.Lebbie
Glad to help. Think of this as merely a way of "pushing back" the use of #selector to an earlier stage of the action. Instead of doing it in the callee, we do it in the caller.Supersensitive
Thank you, @matt. It changed the dynamics of my helper classes, big time.Tequila
W
-4

You could also pass Functions as parameters in swift -- the parameter is essentially the method signature. Here's a simple example that will run in a Playground:

func myFunc(s:String) -> String
{
    return ("Hello \(s)")
}

func myOtherFunc(s:String) -> String
{
    return ("Goodbye \(s)")
}

func someOtherFunc(aFunction:String -> String) -> String
{
    return aFunction("test")
}

print(someOtherFunc(myFunc))
print(someOtherFunc(myOtherFunc))

I am not sure that this is what you want, but it's helpful at times. You could then do:

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

and then change the self.getBtn method to expect the function. Something like this:

func funcOne()
{
    print("Executing func one")
}

func getBtn(i: String, f: () -> ()) -> UIBarButtonItem
{
    let btn: UIButton = UIButton();
    btn.frame=CGRectMake(0,0,30,30)
    btn.setBackgroundImage(UIImage(named:i), forState: UIControlState.Normal)
    btn.addTarget(self, action: f, forControlEvents:.TouchUpInside)
    let barBtn = UIBarButtonItem(customView: btn)
    return barBtn;
}
Whorehouse answered 19/8, 2016 at 16:56 Comment(2)
You can pass a function as a parameter within Swift, but you cannot pass a function where an Objective-C selector is expected (i.e. as the action: argument), so this won't work.Supersensitive
It's unfortunate to show untested code, especially when it doesn't compile.Supersensitive

© 2022 - 2024 — McMap. All rights reserved.