在Swift中向函数传递选择器(函数名)

15

我想将一个函数的选择器传递给另一个函数。目前我只是传递字符串并执行多个if语句。如果我能把实际的函数选择器传递给函数,我可以消除所有的if语句。

我的当前函数:

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;
}

使用方法:

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

我希望能够做到的:

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;
}

使用方法:

items.append(self.getBtn("checkmark",f:self.funcOne));
2个回答

28
< p >< code >#selector() 语法的目的是为了避免您必须将选择器写成文本字符串而可能出现错误,这种方法容易出错。尽管如此,您仍可以编写 Selector(f) 而不是使用 #selector() 语法。

然而,如果 f 本身被定义为 Selector 类型,那就更好了:

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

这样,你可以在调用时继续使用 #selector,但需要这样做:

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

getBtn中,你只需要直接将f作为按钮的操作传递即可。


谢谢你把它搞定了。我没有收到任何错误。正是我所希望的。现在将在构建中进行测试。 - Works for a Living
很高兴能够帮忙。把这看作是将使用#selector的操作推迟到更早的阶段的一种方式。我们不是在被调用者中执行,而是在调用者中执行。 - matt
谢谢你,@matt。这大大改变了我的辅助类的动态。 - iSofia

-3
你也可以在Swift中将函数作为参数传递 -- 参数本质上是方法签名。这里有一个简单的示例,可以在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))

我不确定这是否是您想要的,但有时它很有帮助。然后您可以执行以下操作:

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

然后将self.getBtn方法更改为期望该函数。类似于这样:

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;
}

在Swift中,您可以将函数作为参数传递,但是您不能传递一个函数作为期望Objective-C选择器的参数(即作为“action:”参数),因此这行不通。 - matt
4
展示未经测试的代码是不幸的,特别是当它无法编译时。 - matt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接