问题
I have tried to implement the custom function with the closure. But it's does not supported by #selector
.
Here's an example:
class Core: NSObject {
static let shared:Core = Core.init()
func button(viewController: UIViewController, button: UIButton, title: String, color: UIColor, completion: () -> Void) {
button.layer.cornerRadius = button.bounds.width / 2
button.setTitle(title, for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.backgroundColor = color
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18)
button.addTarget(viewController, action: #selector(completion()), for: .touchUpInside)
}
}
The Xcode gives me a build time issue:
Argument of '#selector' does not refer to an '@objc' method, property, or initializer
回答1:
A selector is a string that's used to identify methods, properties, initializers in the Objective C runtime. When you use a notation like #selector(SomeClass.SomeMethod(withParam:AndParam:)
, you're specifying the selector in a format that the compiler can parse easily and verify to be correct. But ultimately, that would just be reduced down into a C string like: "SomeMethodwithParam:AndParam:"
.
Essentially, every class has a dictionary which maps selectors to the function pointers of the code that implements them. When a selector is used to invoke a function, the Objective C runtime searches the method table for the class in question, and looks up the method implementation corresponding to the given selector.
There's no way for this process to work with closures, which are anonymous by definition. Thus, you can only use selectors to refer to methods, properties, initializers that are registered with the Objective C runtime (which is what @objc
does, implicitly or explicitly).
回答2:
You can not call a completion block in this way. A #selector
is a defined function in a class somewhere in your project. A closure is not a valid selector.
Declare your completion block as a typealias
and store the completion as a property of your class. Then you will want to call this completion from a defined function:
// Declare your completion as typealias
typealias YourCompletion = () -> Void
// At top of your class
var completion: YourCompletion?
// Then in your function declare the completion: parameter to be of type YourCompletion
func button(viewController: UIViewController, button: UIButton, title: String, color: UIColor, completion: YourCompletion) {
// Assign completion as property
self.completion = completion
// Configure your button
button.layer.cornerRadius = button.bounds.width / 2
button.setTitle(title, for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.backgroundColor = color
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18)
// Have your button action be the function you'll make below
button.addTarget(viewController, action: #selector(self.callCompletion), for: .touchUpInside)
}
func callCompletion() {
if let completion = self.completion {
// Call completion
completion()
}
}
来源:https://stackoverflow.com/questions/43485303/the-selector-is-not-compatible-with-the-closure