转载

Objective-C与Swift混编实践

前言

由于Swift的语法趋于稳定,目前本人负责的项目也已经在小范围地引入Swift。关于混编过程中遇到的各种思考与选择,胡波的 这篇文章 已经阐述得得比较全面了,看完文章回头看自己在混编过程中的各种选择,与胡先生的看法是一致的。在此梳理一下一些值得注意的小细节。

Optional

基于Objective-C的工程一般都是将JSON转为Model,把数据以Model的形式在对象之间传递。当服务器传过来的值为空或者类型错误时,大部分解析框架都会将相对应的值置为nil。我们知道在Objective-C的世界里,向nil发送消息是不会引发任何错误的。

Objective-C中没有任何问题的属性:

@property (nonatomic, strong) NSString *GroupName; 

到了Swift的世界里,变成了:

Objective-C与Swift混编实践

没错,隐式解析的存在,导致了容错能力的下降。只要服务端回传的参数中有一个空字段,必然引发Crash。这简直是自寻死路。

因此我们需要在Objective-C中,将属性标上 nullable ,这样Swift中该属性变成了optional,然后采用 if let 或者 guard let 来安全地拆包。

即使业务上决定了某些字段绝对不可能为null,也仍然要将其设为nullable。校验任何外来输入是编程时的基本准则之一。

想必大家也想到了,这样一来,在混编的过程中,if let充斥着Swift的代码,虽然保证了安全,但一定程度上降低了开发效率。个人还在不断摸索解决这个问题的方法。

Selector

在Objective-C的世界里, @selector 是我们的老朋友了。但到了Swift中我们不得不这样来用 Selector :

self.addTarget(self, action: "resignFristResponder", forControlEvents: .EditingDidEndOnExit) 

如果不仔细看,一定不会发现上面的代码中我错将 resignFirstResponder 写成了 resignFristResponder 。这在编译时不会出现任何提醒,但到了运行时会引起崩溃。

幸运的是,Swift2.2用 #selector 关键字替代了字符串反射。此时拼写错误可以被编译期正确地纠正了--因为编译期会检查到方法不存在,并报一个error。

你可以这样写一个不带参数的selector:

#selector(resignFirstResponder) 

如果是带参数的selector,则会稍微特别一点:

#selector(textFieldDidChange(_:) 

采用下划线来忽略参数名,但记得保留分号。

有一点需要注意一下,Selector只支持反射Objective-C的方法,如果想要让#selector能正确识别Swift的方法,需要在方法前面加上 @objc 关键字

命名

Swift得益于Module而避免了类的命名冲突。在用Swift编写代码的时候,应当遵循Apple官方的命名规范。例如类命名不需要在类名前加前缀。如果类也需要在Objective-C中被调用,可以用@objc关键字来为Objective-C生成对应的类名。

@objc(PSLimitedTextField) public class LimitedTextField: UITextField { 

同时API的设计也建议按照官方的 指导原则 来。我从开始写Objective-C时就尽量模仿Apple的命名方式,后来在Objective-C到Swift的自动桥接上尝到了甜头。比如说:

- (instancetype)initWithName:(NSString *)name; 

被自动桥接成了

init(name: String) 

工厂方法

如果仔细对比Objective-C和Swift的接口,你会发现有的类的工厂方法消失了,有的类的还在。这同样是由于命名的问题所导致的。Apple将那些同类名一致的工厂方法桥接成了init方法,将一些默认单词(default,standard,shared etc.)开头的工厂方法保留了下来。

如: [NSDate date] 变成了 NSDate() .

[NSUserDefaults standardUserDefaults] ,保留了下来,变成了 NSUserDefaults.standardUserDefaults()

PSNumberPad 就因为工厂方法的命名问题,没能自动桥接成Swift的方法。因此,在混编过程中,如果Objective-C的组件有可能被Swift调用的,需要妥善设计接口以便自动桥接。一个最佳实践是,多采用 convince initialzer 替代工厂方法。

参考资料

在混编的过程中,大部分问题你可以在 这里 找到想要的答案。再一次感谢Apple完善的文档!

原文  http://shengpan.net/usingswiftwithobjc/
正文到此结束
Loading...