我们以斗鱼APP为例,总结swift3.0以及swift4.0转换过程中遇到的问题。
一、方法重写问题
1、swift 3.0在子类中的方法重写
我们RecommendVC类继承自BaseAnchorVC,BaseAnchorVC中包含setupUI方法,然后再子类RecommendVC的继承中重写setupUI方法,这样是没有问题的。
extension RecommendVC {
override func setupUI(){
//调用父类方法
super.setupUI()
collectionView.addSubview(cycleView)
collectionView.addSubview(gameView)
//拓宽collectionView的高度
collectionView.contentInset = UIEdgeInsets(top: kCycleViewH+kGameViewH, left: 0, bottom: 0, right: 0)
}
}
2、swift4.0方法的重写
在swift4.0方法中不可使用这种方法重写,否则会报错。如下图所示:
由于无法重写方法,所以我们目前就不重写父类方法,而是重新给子类定义一个方法使用。
二、KVC自动赋值问题
1、在swift3.0中,我们从服务器获取数据之后,进行字典转模型,然后使用KVC自动赋值。
注意:由于使用了KVC自动赋值,在项目中极有可能出现我们模型中没有定义的key导致的崩溃导致的崩溃,所以我们重写func setValue(_ value: Any?, forUndefinedKey key: String) 方法,防止崩溃。
class CycleModel: NSObject {
var title : String = ""
var pic_url : String = ""
var anchor : AnchorModel?
//didSet自动监控值的变化,使用guard进行检验
var room :[String :Any]?{
didSet{
guard let room = room else {
return
}
anchor = AnchorModel(dict: room)
}
}
init(dict : [String : Any]) {
super.init()
setValuesForKeys(dict)
}
//防止在KVC赋值时有找不到key导致的崩溃
override func setValue(_ value: Any?, forUndefinedKey key: String) {}
}
2、在swift4.0中,直接这样使用无效。
我们必须在属性前添加@objc,只有这样才能满足OC的KVC赋值。
class CycleModel: NSObject {
@objc var title : String = ""
@objc var pic_url : String = ""
@objc var anchor : AnchorModel?
@objc var room :[String :Any]?{
didSet{
guard let room = room else {
return
}
anchor = AnchorModel(dict: room)
}
}
init(dict : [String : Any]) {
super.init()
setValuesForKeys(dict)
}
override func setValue(_ value: Any?, forUndefinedKey key: String) {
}
}
@objc知识扩展
- @objc 作用
1、fileprivate 或者 private 保证方法私有 能在同一个类 或者 同一个文件(extension)中访问这个方法 如果定义为private 那么只能在一个类中访问 不能在类扩展中访问。
2、允许这个函数在“运行时”通过oc的消息机制调用。比如上面的KVC赋值属性就必须使用@objc。
三、swift中的@objc的作用
swift为静态语言,每个函数在编译期间就可以确定。因此在编译完成后可以检测出没有被调用到的swift函数,优化删除后可以减小最后二进制文件的大小。相较于OC是一个杀手级的特性。
那么,为什么OC没有这个特性嫩?
那是因为OC是动态语言,调用函数是在运行时通过发送消息调用的。所以在编译期并不知道这个函数是否调用到,所以全部的方法都会保留。
- 混合开发中的问题
swift中的函数怎么知道是否被OC调用了呢?
出于安全起见,只能保留所有有可能会被OC调用的swift函数,然后标记为@objc。
在 swift 3 中除了手动添加 @objc 声明函数支持 OC 调用还有另外一种方式:继承 NSObject。class 继承了 NSObject 后,编译器就会默认给这个类中的所有函数都标记为 @objc ,支持 OC 调用。然而在实际项目中,一个 swift 类虽然继承了 NSObject,但是其中还是有很多函数不会在 OC 中被调用,这里有很大的优化空间。于是根据 SE160 的建议,苹果修改了自动添加 @objc 的逻辑:一个继承 NSObject 的 swift 类不再默认给所有函数添加 @objc。只在实现 OC 接口和重写 OC 方法时才自动给函数添加 @objc 标识。
XCode 9会在运行过程中自行检测类中函数是被 OC 调用,然后提示添加 @objc。下图中的 vc 是 swift 中的类,showStatus 也是 swift 函数,现在编译器会提示需要手动添加 @objc: