The #selector is not compatible with the closure?

不打扰是莪最后的温柔 提交于 2020-01-04 03:01:06

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!