[英]Passing closure in swift as parameter to be used by selector in function
I am trying to create a generic button creation function into which I pass a closure that represents the action that results as a result of clicking on the button.我正在尝试创建一个通用按钮创建 function,我将一个闭包传递到其中,该闭包表示单击按钮后产生的操作。 My code is below.
我的代码如下。 However, I get the following error: Argument of #selector cannot refer to property.
但是,我收到以下错误:#selector 的参数无法引用属性。 Any suggestions for a workaround?
有什么解决方法的建议吗? I don't want to write separate functions for which everything else is the same except for the target action.
我不想编写单独的函数,除了目标操作之外,其他所有内容都相同。
func myButton(textColor tColor:UIColor , title:String,
_ buttonFcn: (UIButton) -> Void,
titleSize:CGFloat=30) -> UIButton {
let newButton = UIButton(type: .System)
let bgColor = UIColor(red:204/255, green:204/255, blue:204/255, alpha:1.0)
newButton.backgroundColor = bgColor
newButton.setTitle(title, forState: .Normal)
newButton.setTitleColor(tColor, forState: .Normal)
newButton.titleLabel?.font = newButton.titleLabel?.font.fontWithSize(titleSize)
newButton.addTarget(self, action:#selector(buttonFcn),
forControlEvents:
UIControlEvents.TouchUpInside)
return newButton
}
The problem is that the target-action mechanism is an Objective-C mechanism, and therefore is predicated on the notion that the action selector is a method of an object . 问题在于目标动作机制是一种Objective-C机制,因此基于动作选择器是一种对象 方法的概念来进行判断。 You need, therefore, to have some NSObject-based object that has this function as a method , and which can then serve as the target.
因此,您需要具有一些基于NSObject的对象 ,该对象具有将此功能用作方法 ,然后可以用作目标。
Thus, if what differs in every case is the target and the action, what you need to pass is a reference to the target along with the selector string . 因此,如果目标和操作在每种情况下都不同,那么您需要传递的是对目标的引用以及选择器字符串 。 Swift will squawk at this, but if you know how to form a selector string correctly you can certainly get away with it;
Swift会对此之以鼻,但是,如果您知道如何正确形成选择器字符串,那么您当然可以摆脱它; you just won't be able to use the
#selector
syntax, and so you will risk crashing if you form the selector string incorrectly. 您将无法使用
#selector
语法,因此,如果输入格式不正确,可能会导致崩溃。 But it's the kind of thing we used to do all the time in the old Objective-C days, so go right ahead if that's your aim. 但这是我们在过去的Objective-C时代一直做的事情,因此,如果这是您的目标,那就继续吧。
Totally artificial but working example: 完全人为但可行的示例:
func buttonMaker(target:NSObject, selectorString:String) -> UIButton {
let b = UIButton(type:.system)
b.setTitle("Testing", for: .normal)
b.addTarget(target, action: Selector(selectorString), for: .touchUpInside)
b.sizeToFit()
return b
}
And here's how to call it from a view controller: 这是从视图控制器调用它的方法:
func doButton(_ sender:Any) {
print("ha!")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let b = buttonMaker(target:self, selectorString:"doButton:")
b.frame.origin = CGPoint(x:100, y:100)
self.view.addSubview(b)
}
And when we tap the button, we don't crash (rather, we print "ha"), because I know how to make selector strings correctly. 而且当我们点击按钮时,我们不会崩溃(而是打印“ ha”),因为我知道如何正确制作选择器字符串。 But, as you can see, to accomplish this I had to give up the use of
#selector
altogether, so safety is out the window. 但是,正如您所看到的,要实现此目的,我必须完全放弃使用
#selector
,因此安全性不在考虑之列。 If I had written my selector string incorrectly — for instance, if I had spelled it wrong, or omitted the colon — we'd have crashed on the button tap, just like we used to all the time before Swift #selector
and Objective-C @selector
were invented. 如果我没有正确输入选择器字符串(例如,如果我拼写错误或省略了冒号),我们将在按钮点击时崩溃,就像我们在Swift
#selector
和Objective-C之前一直都一样@selector
被发明了。
If your deployment target is iOS 14 or later, you can use the addAction
method instead of addTarget
.如果您的部署目标是 iOS 14 或更高版本,您可以使用
addAction
方法而不是addTarget
。 The addAction
method lets you use a closure instead of a selector: addAction
方法允许您使用闭包而不是选择器:
func myButton(
textColor: UIColor,
title: String,
titleSize: CGFloat = 30,
_ handler: @escaping (UIButton) -> Void
) -> UIButton {
let button = UIButton(type: .system)
button.backgroundColor = UIColor(red: 204/255, green: 204/255, blue: 204/255, alpha: 1.0)
button.setTitle(title, for: .normal)
button.setTitleColor(textColor, for: .normal)
button.titleLabel?.font = button.titleLabel?.font.withSize(titleSize)
let action = UIAction { action in
guard let button = action.sender as? UIButton else { return }
handler(button)
}
button.addAction(action, for: .touchUpInside)
return button
}
iOS 14 was released on 2020-09-16 and supports iPhone 6S and later devices. iOS 14于2020-09-16发布,支持iPhone 6S及之后的设备。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.