swift 中,protocol的optional方法
来源:互联网 发布:品茗软件是什么意思 编辑:程序博客网 时间:2024/05/04 02:55
swift推出一年多了,断断续续学了一些,一直没有真正引入自己的项目中。 最近准备做一个 Today Extension,恰好是一个机会可以完整的使用swift开发。刚刚做了几天,就发现又一次被Apple忽悠了,感觉就像iOS6.0时代的AutoLayout,经常掉坑儿里。 尤其是swift和objc的interoperability,最简单、也是困扰我时间最长的就是protocol中的optional方法了。
在Objective-C 中,protocol的optional方法定义和使用都很直观,如下:
定义协议:
@protocol ErSessionDelegate
@optional
- (void) didFinishReceive:(ErSession* sender);
- (void) didFailedReceive:(ErSession* sender);
@end
声明变量:
@property (nonatomic, unsafe_unretained) id<ErSessionDelegate> delegate;
调用:
if ([_delegate respondsToSelector:@selector(didFinishReceive:)]) {
[_delegate didFinishReceive:self];
}
遵守该protocol的类:
@interface DataSyncTask:NSObject <ErSessionDelegate>
@end
@implementation
- (void) didFinishReceive:(ErSession* sender) {
//
}
- (void) didFailedReceive:(ErSession* sender) {
//
}
@end
在swift中,按照上面的代码翻译了一遍:
定义协议:
protocol ErSessionDelegate {
optional func didFinishReceive(sender:ErSession)
optional func didFailedReceive(sender:ErSession)
}
声明变量:
var delegate: ErSessionDelegate?
调用:
self.delegate?.didFinishReceive?(self)
遵守该protocol的类:
class DataSyncTask: ErSessionDelegate {
func didFinishReceive(sender:ErSession) {
//
}
func didFailedReceive(sender:ErSession) {
//
}
}
基本上一一映射,只是语法上的变化而已。
在swift的 “定义协议” 部分,遇到了一个编译错误: ‘optional’ can only be applied to members of an @objc protocol 。 当时不明白什么意思, 就按照建议加上了@objc , 如下:
@objc protocol ErSessionDelegate {
optional func didFinishReceive(sender:ErSession)
optional func didFailedReceive(sender:ErSession)
}
很好,到此为止,编译通过,一切顺利。
开始运行app,呃,DataSyncTask中的两个回调函数(didFinishReceive, didFailedReceive)却从来不被调用,
单步跟踪,一切正常, self.delegate?.didFinishReceive?(self) 执行时,所有的变量也是正常的。怎么回事呢?
把它拆开, 强制unwrap:
if let delegate = self.delegate {
delegate.didFinishReceive!(self)
}
发生运行时错误,程序崩溃在这一行 delegate.didFinishReceive!(self)
运行时栈的第4层是: -[SwiftObject doesNotRecognizeSelector:]
delegate中明明已经定义了didFinishReceive,为什么还会有这个错误呢?
看了一堆文档,终于找到了原因,就是上面那个编译错误,加上 @objc 才编译通过的问题。
简单来说,swift中的protocol原生不支持optional(为什么呢?),必须依赖objective-C的运行时才能支持。
那么,在protocol中声明optional方法时,必须要加上@objc属性。
对于: self.delegate?.didFinishReceive?(self)
本质上来讲,第二个问号是通过ObjC的respondsToSelector: 方法实现的。所以,在上面的 DataSyncTask 类中实现该协议时,也需要让ObjC运行时能够识别那两个函数。(深入的技术细节请看下面的参考文档。)
具体实现方法有三种:
1. 让 DataSyncTask 继承 NSObject
class DataSyncTask:NSObject, ErSessionDelegate {
...
}
2. 给DataSyncTask 加上@objc属性
@objc class DataSyncTask: ErSessionDelegate {
...
}
3. 给相关函数加上 @objc属性
class DataSyncTask: ErSessionDelegate {
@objc func didFinishReceive(sender:ErSession) {
//
}
@objc func didFailedReceive(sender:ErSession) {
//
}
}
三种方法任选其一。各有各的好处。前两者有些大才小用,因为,那相当于让整个类的每一个方法和属性都具有了 objc的能力。 第三种也有一个小缺点,就是,当有子类继承DataSyncTask时,如果重载了这两个方法,也需要加上@objc,稍稍有点麻烦而已。
就swift语言本身来讲,确实是个优雅的、强大的、现代感十足的语言。本来以为可以逐渐摆脱老态龙钟的objC,可是,swift居然如此重度依赖Objective-C。想想 Cocoa framework 吧,整个基于NSObject, 而swift离开他可是寸步难行。
参考文档:
http://www.csdn.net/article/2015-02-15/2823979-swift-objc-protocol
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-XID_25
http://www.csdn.net/article/2015-02-04/2823831-swift-objc-and-dynamic
0 0
- swift 中,protocol的optional方法
- Swift中定义protocol,定义optional方法
- swift protocol optional可选方法
- Swift的Optional、if let、protocol、closure
- Swift Protocol optional
- protocol的optional检查。
- 如何理解Swift中Optional的 ! 和 ?
- 如何理解Swift中Optional的!和?
- Swift的Optional类型
- 深入浅出Swift的Optional ?!
- Swift的optional
- Swift的Optional、Array
- Swift的Optional
- swift中出现Optional("xxx")
- swift中(Optional)类型
- unexpectedly found nil while unwrapping an Optional value的解释 && Swift中Optional
- swift3.0 unexpectedly found nil while unwrapping an Optional value的解释 && Swift中Optional
- Swift 中 optional 值的取值问题
- 实现一个函数,计算一个字符串的值,该字符串中只有+ - * /四种运算符, 没有括号。 //参数mathString:要计算的字符串; //返回值:把计算出来的结果返回 例如:传入:@"1+2-1
- 结构型模式之代理模式
- python是一门动态语言
- (转载)在C++程序中使用pbrt进行渲染
- SAP成本收集器
- swift 中,protocol的optional方法
- POJ 3414 Pots
- groovy gsp g标签
- 机房收费系统之结账
- DNS DDoS攻击事件分析
- 学不好java,只怪你不知道自己错在哪
- AIDL进程间传递复杂数据类型—AIDL传递android.os.Parcelable接口
- jeecms栏目模型和内容模型的使用以及对应前台的标签中的属性名
- HBase的安装