[置顶] Swift3.2 到Swift4 的升级工作(要处理SDK API的bug)
2018-01-17 18:20
621 查看
最近完成了公司项目由Swift3.2 -> Swift4的升级工作,记录一下。
这里将Swift4较Swift3.2的新特性以及必要的处理列出来:
1,private关键字作用域扩大到整个文件。
说明:可以用private替代fileprivate了
处理建议:考虑到private没有向后兼容性(在swift3.2及之前版本无法在extension中使用),所以建议保留原来的fileprivate关键字。
2,扩展Key Path的写法
说明:
Swift 3.2中Key Path写法:
Swift4中增加的写法:
处理建议:代码可以不用改,见了\的用法认识就可以。
3,关于@objc的使用
说明:
Swift编译器会推断需要暴露给OC的函数(所有继承于NSObject的类的函数),并为其增加@objc关键字修饰。这样做的问题有:
(1)增大二进制文件大小。
(2)程序员不知道编译器何时会推断为需要增加@objc
用Swift4编译代码时,在check dependencies这一步,提示:
The use of Swift 3 @objc inference in Swift 4 mode is deprecated. Please address deprecated @objc inference warnings, test your code with “Use of deprecated Swift 3 @objc inference” logging enabled, and then disable inference by changing the “Swift 3 @objc Inference” build setting to “Default” for the “XXX” target.
按照提示将xxx target - build setting- Swift 3 @objc Inference 由On改为Default之后,#selector的函数以及dynamic变量如果没有用@objc修饰的话,会报错:
Argument of ‘#selector’ refers to instance method ‘xxx()’ that is not exposed to Objective-C
给#selector中的函数和dynamic变量前面加上@objc就可以了。
处理建议:必须按照说明中的方法修改,否则编译报错。
4,结构体UILayoutPriority中的运算符重载被删除
说明:
setContentCompressionResistancePriority(_:for:)等方法的参数类型是结构体UILayoutPriority。
Swift3.2写法:
Swift4写法:
处理建议:必须按照说明中的方法修改,否则编译报错。
5,NSAttributedString相关OC的全局变量无法在Swift4中继续使用
说明:
看下这段代码:
这段代码在Swift3.2上编译无问题,但是在Swift4上报错:
Cannot convert value of type ‘NSAttributedStringKey’ to expected dictionary key type ‘String’
查了SDK,NSFontAttributeName是OC中的全局变量名,在Swift中相应的是NSAttributedStringKey.font。看来Swift4中严格限制了OC中的全局变量在Swif4中的使用。
以下是Swift4中的写法:
处理建议:必须按照说明中的方法修改,否则编译报错。
6,更严格的Block参数检查
说明:
Swift4中对Block中参数的个数进行了严格的检查,即使是用_表示的未使用参数,个数也要严格对应才能编译通过。
例如,Kingfisher中的Block定义
使用方式:
上面的代码Swift3.2中编译正常,Swift4中报错:
Cannot convert value of type ‘(_) -> ()’ to expected argument type ‘DownloadProgressBlock?’ (aka ‘Optional<(Int64, Int64) -> ()>’)
修正方式:
处理建议:使用时需要符合block中参数的个数
7,AVCaptureDevice、AVCaptureSession、AVMediaType等类中的全局变量无法在Swift4中继续使用
说明:
会有编译error。
处理建议:
消去编译error,工作并没有完成。你如果测试一下你的Barcode功能的话,你会发现原来运行的完好的扫码功能,扫不出来结果了。原因是回调函数不被调用了:
苹果大大真厉害,原来是偷偷的将回调函数改为了,还有没有测试人员了??!!:
修改了函数名后,好用了。参考:
https://stackoverflow.com/questions/46011211/barcode-on-swift-4/46027337#46027337
在参考文档中讲解的下面的功能点经证实在Swift3.2就已经有了,并不是Swif4新增加的功能:
1,有些教程中说“类型和协议的组合类型”是Swift4中新增加的特性,这是错误的,在Swift3.2就已经有个这个特性,在代码中指定类型为(类型 & 协议)是不会报错的。
2,用”“”控制字符串可以实现多行字符串字面量。
3,对于字典集合的顺序初始化,过滤等内容。
参考:
1,最全的 Swift 4 新特性解析 https://www.jianshu.com/p/c4f5db08bcab
2,What’s New in Swift 4? https://www.raywenderlich.com/163857/whats-new-swift-4
这里将Swift4较Swift3.2的新特性以及必要的处理列出来:
1,private关键字作用域扩大到整个文件。
说明:可以用private替代fileprivate了
处理建议:考虑到private没有向后兼容性(在swift3.2及之前版本无法在extension中使用),所以建议保留原来的fileprivate关键字。
2,扩展Key Path的写法
说明:
Swift 3.2中Key Path写法:
class Kid: NSObject { var nickname: String = "" var age: Double = 0.0 var friends: [Kid] = [] init(nickname: String, age: Double) { self.nickname = nickname self.age = age } } class ViewController { func testKeyPath() { var ben = Kid(nickname: "Benji", age: 5.5) let kidsNameKeyPath = #keyPath(Kid.nickname) ben.setValue("Ben", forKeyPath: kidsNameKeyPath) } }
Swift4中增加的写法:
func testKeyPath() { let ben = Kid(nickname: "Benji", age: 5.5) let kidsNameKeyPath = \Kid.nickname ben[keyPath: \Kid.nickname] = "Ben" }
处理建议:代码可以不用改,见了\的用法认识就可以。
3,关于@objc的使用
说明:
Swift编译器会推断需要暴露给OC的函数(所有继承于NSObject的类的函数),并为其增加@objc关键字修饰。这样做的问题有:
(1)增大二进制文件大小。
(2)程序员不知道编译器何时会推断为需要增加@objc
用Swift4编译代码时,在check dependencies这一步,提示:
The use of Swift 3 @objc inference in Swift 4 mode is deprecated. Please address deprecated @objc inference warnings, test your code with “Use of deprecated Swift 3 @objc inference” logging enabled, and then disable inference by changing the “Swift 3 @objc Inference” build setting to “Default” for the “XXX” target.
按照提示将xxx target - build setting- Swift 3 @objc Inference 由On改为Default之后,#selector的函数以及dynamic变量如果没有用@objc修饰的话,会报错:
Argument of ‘#selector’ refers to instance method ‘xxx()’ that is not exposed to Objective-C
给#selector中的函数和dynamic变量前面加上@objc就可以了。
处理建议:必须按照说明中的方法修改,否则编译报错。
4,结构体UILayoutPriority中的运算符重载被删除
说明:
setContentCompressionResistancePriority(_:for:)等方法的参数类型是结构体UILayoutPriority。
Swift3.2写法:
self.detail1Label.setContentCompressionResistancePriority(UILayoutPriorityDefaultLow-10, for: UILayoutConstraintAxis.horizontal) self.detail2Label.setContentHuggingPriority(UILayoutPriorityRequired, for: UILayoutConstraintAxis.horizontal)
Swift4写法:
self.detail1Label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: UILayoutPriority.RawValue(Int(UILayoutPriority.defaultLow.rawValue)-10)), for: UILayoutConstraintAxis.horizontal) self.detail2Label.setContentHuggingPriority(UILayoutPriority.required, for: UILayoutConstraintAxis.horizontal)
处理建议:必须按照说明中的方法修改,否则编译报错。
5,NSAttributedString相关OC的全局变量无法在Swift4中继续使用
说明:
看下这段代码:
let textMATString = NSMutableAttributedString(string: "abcd") let titleOptions: [String : Any] = [NSFontAttributeName : UIFont.systemFont(ofSize: 12)] textMATString.addAttributes(titleOptions, range: NSMakeRange(0, 4))
这段代码在Swift3.2上编译无问题,但是在Swift4上报错:
Cannot convert value of type ‘NSAttributedStringKey’ to expected dictionary key type ‘String’
查了SDK,NSFontAttributeName是OC中的全局变量名,在Swift中相应的是NSAttributedStringKey.font。看来Swift4中严格限制了OC中的全局变量在Swif4中的使用。
以下是Swift4中的写法:
let titleOptions: [NSAttributedStringKey : Any] = [NSAttributedStringKey(rawValue: NSAttributedStringKey.font.rawValue) : UIFont.systemFont(ofSize: 12)]
处理建议:必须按照说明中的方法修改,否则编译报错。
6,更严格的Block参数检查
说明:
Swift4中对Block中参数的个数进行了严格的检查,即使是用_表示的未使用参数,个数也要严格对应才能编译通过。
例如,Kingfisher中的Block定义
DownloadProgressBlock = ((_ receivedSize: Int64, _ totalSize: Int64) -> ())
使用方式:
KingfisherManager.shared.retrieveImage(with: url, options: options, progressBlock: {_ in}, completionHandler: { [weak self] (image, error, cacheType, url) in
上面的代码Swift3.2中编译正常,Swift4中报错:
Cannot convert value of type ‘(_) -> ()’ to expected argument type ‘DownloadProgressBlock?’ (aka ‘Optional<(Int64, Int64) -> ()>’)
修正方式:
KingfisherManager.shared.retrieveImage(with: url, options: options, progressBlock: {_, _ in}, completionHandler: { [weak self] (image, error, cacheType, url) in or KingfisherManager.shared.retrieveImage(with: url, options: options, progressBlock: nil, completionHandler: { [weak self] (image, error, cacheType, url) in
处理建议:使用时需要符合block中参数的个数
7,AVCaptureDevice、AVCaptureSession、AVMediaType等类中的全局变量无法在Swift4中继续使用
说明:
会有编译error。
处理建议:
消去编译error,工作并没有完成。你如果测试一下你的Barcode功能的话,你会发现原来运行的完好的扫码功能,扫不出来结果了。原因是回调函数不被调用了:
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!)
苹果大大真厉害,原来是偷偷的将回调函数改为了,还有没有测试人员了??!!:
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection)
修改了函数名后,好用了。参考:
https://stackoverflow.com/questions/46011211/barcode-on-swift-4/46027337#46027337
在参考文档中讲解的下面的功能点经证实在Swift3.2就已经有了,并不是Swif4新增加的功能:
1,有些教程中说“类型和协议的组合类型”是Swift4中新增加的特性,这是错误的,在Swift3.2就已经有个这个特性,在代码中指定类型为(类型 & 协议)是不会报错的。
2,用”“”控制字符串可以实现多行字符串字面量。
3,对于字典集合的顺序初始化,过滤等内容。
参考:
1,最全的 Swift 4 新特性解析 https://www.jianshu.com/p/c4f5db08bcab
2,What’s New in Swift 4? https://www.raywenderlich.com/163857/whats-new-swift-4
相关文章推荐
- Xcode升级4.4后的Bug处理
- [置顶] 百度OCR文字识别API使用心得===com.baidu.ocr.sdk.exception.SDKError[283604]
- [置顶] 【android】Android中图形图片及处理相关Api的小总结
- Platform SDK 字符串处理 API
- [置顶] API相关工作的个人总结_工作中琐碎细节的总结二
- (zt)Flex SDK 3.2和Flex Builder 3.0.2升级
- [置顶] 2013年工作中遇到的20个问题(Bug):161-180
- swift3.2升级到swift4.0 扫码不走回调方法
- WindowsPhone开发 +使用Live SDK相关API操作SkyDrive + IsolatedStorageSettings的Bug。
- [置顶] 升级到XCode9(BaseSDK:iOS11)的各种坑 持续更新中
- [置顶] API相关工作过往的总结之Sandcastle简要使用介绍
- [置顶] Swift 调试bug问题记录(长期记录)
- [置顶] Zabbix3.2告警升级机制
- Revit二次开发——加快过滤速度,以及对ElementIntersectsSolidFilter的API的Bug的处理办法
- 一个ArcGIS Javascript API的BUG和处理办法 - 调用两次Draw工具条deactivate方法导致的错误
- esp 8266 之坑-- API 和SDK的bug
- flex SDK 3.2升级到 3.5 1046错误 charts组件无法使用
- Swift学习记录 - 关于Alamofire手动导入以及pod导入bug处理
- 自己发现的SDK 自带的apidemo中的一个bug
- Android SDK Manager无法更新升级情况处理办法