如何解决“歧义使用”编译错误与Swift #selector语法?

前端之家收集整理的这篇文章主要介绍了如何解决“歧义使用”编译错误与Swift #selector语法?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
假设我在类中有这两个方法
func test() {}
func test(sender:AnyObject?) {}

现在我想使用Swift 2.2的新的#selector语法来创建一个与第一个方法func test()相对应的选择器。我该怎么做?当我尝试这:

let selector = #selector(test) // error

…我得到一个错误,“不明确使用test()。但是如果我这样说:

let selector = #selector(test(_:)) // ok,but...

错误消失了,但我现在指的是错误方法,一个参数。我想参考一个没有任何参数。我该怎么做?

[注:示例不是人工的。 NSObject有Objective-C拷贝和拷贝:实例方法,Swift copy()和copy(sender:AnyObject?所以问题很容易出现在现实生活中。

您可以通过将您的函数引用转换为正确的方法签名来解决此问题:
let selector = #selector(test as Void -> Void)

(但是,在我看来,你不应该这样做,我认为这种情况是一个错误,揭示Swift的语法参考函数是不够的,我提交了一个错误报告,但没有效果)

只是总结新的#selector语法:

此语法的目的是防止在将选择器作为文字字符串时出现的所有太常见的运行时崩溃(通常是“无法识别的选择器”)。 #selector()接受函数引用,编译器将检查函数是否真的存在,并将为您解析对Objective-C选择器的引用。因此,你不能容易犯任何错误

(编辑:好的,是的,你可以是一个完整的Lunkhead,并将目标设置为一个实例,不实现#selector指定的动作消息编译器不会阻止你,你会崩溃就像在好的旧日子,叹息…)

函数引用可以以三种形式中的任何一种形式出现:

>函数的裸名。如果函数是明确的,这是足够的。因此,例如:

func test(sender:AnyObject?) {}
func makeSelector() {
    let selector = #selector(test)
}

只有一个测试方法,所以这#selector引用它,即使它需要一个参数,#selector没有提及参数。解析的Objective-C选择器,在幕后,仍然会正确地“测试:”(带冒号,表示参数)。
>函数名称及其签名的其余部分。例如:

func test() {}
func test(sender:AnyObject?) {}
func makeSelector() {
    let selector = #selector(test(_:))
}

我们有两个测试方法,所以我们需要区分;符号测试(_ :)解析为第二个,一个带有参数。
>函数名称,带有或不带有其签名的其余部分,加上一个转换以显示参数的类型。从而:

@objc func test(integer:Int) {}
@nonobjc func test(string:String) {}
func makeSelector() {
    let selector1 = #selector(test as (Int) -> Void)
    // or:
    let selector2 = #selector(test(_:) as (Int) -> Void)
}

这里,我们重载了test(_ :)。重载不能暴露给Objective-C,因为Objective-C不允许重载,所以只有其中一个是暴露的,我们可以形成一个选择器只对暴露的选择器,因为选择器是一个Objective-C功能。但是我们仍然必须对Swift进行消歧,而演员也是如此。

(正是这种语言特征被滥用,在我看来是作为上述答案的基础)。

此外,您可能需要帮助Swift解决函数引用,告诉它函数所处的类:

>如果类与这一个相同,或者从这一个超类链向上,通常不需要进一步的解析(如上面的例子所示);可选地,你可以用点表示法(例如#selector(self.test))说自我,在某些情况下你可能需要这样做。
>否则,使用对实现方法的实例的引用,使用点表示法,如在这个现实生活中的示例(self.mp是一个MPMusicPlayerController):

let pause = UIBarButtonItem(barButtonSystemItem: .Pause,target: self.mp,action: #selector(self.mp.pause))

…或者你可以使用类的名称,用点表示法:

class ClassA : NSObject {
    func test() {}
}
class ClassB {
    func makeSelector() {
        let selector = #selector(ClassA.test)
    }
}

(这似乎是一个好奇的符号,因为它看起来像你说测试是一个类方法而不是一个实例方法,但它会正确解析到一个选择器,这是所有重要的。

猜你在找的Swift相关文章