#selector与闭包不兼容?

时间:2017-04-19 02:30:57

标签: swift closures selector func

我试图用闭包实现自定义函数。但是#selector不支持它。

以下是一个例子:

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

Xcode给我一个构建时间问题:

  

'#selector'的参数不是指'@objc'方法,属性或初始值设定项

2 个答案:

答案 0 :(得分:3)

选择器是一个字符串,用于标识Objective C运行时中的方法,属性和初始值设定项。当您使用#selector(SomeClass.SomeMethod(withParam:AndParam:)之类的表示法时,您可以使用编译器可以轻松解析并验证正确的格式指定选择器。但最终,这只会缩小为C字符串,如:"SomeMethodwithParam:AndParam:"

本质上,每个类都有一个字典,它将选择器映射到实现它们的代码的函数指针。当使用选择器来调用函数时,Objective C运行时在方法表中搜索有问题的类,并查找与给定选择器对应的方法实现。

这个过程无法使用闭包,根据定义,闭包是匿名的。因此,您只能使用选择器来引用使用Objective C运行时注册的方法,属性,初始值设定项(@objc隐式或显式执行的操作。

答案 1 :(得分:1)

您无法以这种方式调用完成块。 #selector是项目中某个类的已定义函数。闭包不是有效的选择器。

将完成块声明为typealias并将完成存储为您班级的属性。然后,您将需要从已定义的函数调用此完成:

// 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()
    }
}