Swift中的Selector

Swift中的Selector

前言

Selector做为一个在不少Objective-C设计模式中的重要组成部分,Swift为了保证部分接口的一致性依然保留了这一律念。这篇文章时我在学习这部份内容时的遇到问题的一些总结。设计模式

虽然Swift中依然保留了对Selector的支持。可是在某些地方咱们能够采用更为安全的方式来实现Objective-C中对应的部分。例如:respondsToSelector:performSelector:能够分别使用协议类型的可选链和闭包进行替换。安全

//某个协议 *respondsToSelector:*

//Objcctive-C版本 
if(self.delegate.respondsToSelector(Selector("HanggeSwiftMenuWillAnimateClose:"))){
    self.delegate.HanggeSwiftMenuWillAnimateClose(self)
}

//Swift版本
self.delegate?.HanggeSwiftMenuWillAnimateClose(self)

可是仍是不少像timer和target/action设计模式同样的地方大量的使用了Selector。下面咱们看下这部分的处理。闭包

Swift2.2以前的状况

在Swift2.2版本以前,selector经过一个简单的字符串常量来传递。由于字符串是咱们开发人员手写并且尚未自动补全这增长的程序出差的可能性。app

    let button = UIButton(type: .System)
    button.addTarget(self, action: Selector(“buttonTapped:”), forControlEvents: .TouchUpInside)
    ...
    func buttonTapped(sender: UIButton){ }
    
一个很好的函数命名习惯和风格就是使用控件对象的名称做为函数的前缀。在上面的示例中,函数名称buttonTapped:对应的就是按键buttontapped事件。而且记住要传递惟一一个类型正确的sender参数,由于你有这个对象可是不用,老是好过你须要这个对象可是没有要好。ide

整体上来讲并非很难,可是这里又一些问题须要咱们注意:函数

Selector的可用性:经过selector引出的方法须要暴露给ObjC运行时。若是是继承自NSObject的类那么就已经实现了这个特性,可是若是是纯Swift的类你须要在函数的声明前面加上@objc来进行实现。而且该函数访问级别最起码应该是internal,由于private是没法暴露给运行时的。学习

Selector的名字:由于selectors是一个ObjC中的东西遵循ObjC的方法命名规则,每个参数都有一个冒号(:)。例如,名为test()的selector就是"test",test(this: String)的selector就是"test:",test(this: String, andThat: Int)就是"test:andThat:"。this

Swift2.2中的改进

在Swift2.2中selector已经变得更加安全了。它使用#selector这种语法来实现Selector,这避免了以前使用字符串可能带来的手动输入错误。由于该语法会让编译器会对方法进行检查,不存在的方法是没法经过编译的,这个在以前作法中是作不到的。设计

button.addTarget(self, action: #selector(ViewController.buttonTapped(_:)), forControlEvents: .TouchUpInside)

当你一眼扫过去会发现代码比较长也不是很容易阅读。尤为是若是你的代码中有不少的ViewController类型的类而且在代码中屡次使用同一个Selector,屡次的拷贝/复制这么长的代码或者是修改是否是想一想就很麻烦啊?一种解决方法是:将全部Selector整理放在同一个地方,进行统一的编辑和引用。code

private struct Action {
    static let buttonTapped = 
        #selector(ViewController.buttonTapped(_:))
}
...
button.addTarget(self, action: Action.buttonTapped,       
    forControlEvents: .TouchUpInside)

咱们将全部的Selector做为静态常量放在Action结构里面。这里之因此将Action声明为private是为了防止其它文件里面也定义了一个这样的结构致使编译时候的重定义。

另外一种更为语法糖一些的解决方法就是对Selector进行extension

private extension Selector {
    static let buttonTapped = 
        #selector(ViewController.buttonTapped(_:))
}
...
button.addTarget(self, action: .buttonTapped, 
    forControlEvents: .TouchUpInside)

利用语法特性,咱们不须要使用Selector.buttonTapped,从而使代码更简洁一些,也更装X一些。

相关文章
相关标签/搜索