@wrlqwe
2017-02-06T06:49:27.000000Z
字数 5477
阅读 1445
iOS
xcode提供了转换器,只不过需要人工review
问题:
ambiguous use of 'yy_setTextHighlight'text.yy_setTextHighlight(range, color: UIColor.clear, backgroundColor: UIColor.clear, tapAction: { [weak self] (view: UIView, text: NSAttributedString, range: NSRange, rect: CGRect) in^__ObjC.NSMutableAttributedString:561:15: note: found this candidateopen func yy_setTextHighlight(_ range: NSRange, color: UIColor?, backgroundColor: UIColor?, userInfo: [AnyHashable : Any]? = nil, tapAction: __ObjC.YYTextAction?, longPressAction: __ObjC.YYTextAction? = nil)^__ObjC.NSMutableAttributedString:570:15: note: found this candidateopen func yy_setTextHighlight(_ range: NSRange, color: UIColor?, backgroundColor: UIColor?, tapAction: __ObjC.YYTextAction? = nil)
出错代码如下
text.yy_setTextHighlight(range, color: UIColor.clear, backgroundColor: UIColor.clear, tapAction: { [weak self] (view: UIView, text: NSAttributedString, range: NSRange, rect: CGRect) inself?.showFormAffix(affixModel)})
这是因为两个 Objective-C 方法转换到Swift后,这样调用编译器不知道使用哪个,不省略参数即可解决
text.yy_setTextHighlight(range, color: UIColor.clear, backgroundColor: UIColor.clear, tapAction: { [weak self] (view: UIView, text: NSAttributedString, range: NSRange, rect: CGRect) inself?.showFormAffix(affixModel)}, longPressAction: nil)
如果代码里用到了类似以下的特性:
var l = 10var r: Int? = 5let result = l > r
转换器会在该文件里加入以下代码。
// FIXME: comparison operators with optionals were removed from the Swift Standard Libary.// Consider refactoring the code to use the non-optional operators.fileprivate func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {switch (lhs, rhs) {case let (l?, r?):return l < rcase (nil, _?):return truedefault:return false}}// FIXME: comparison operators with optionals were removed from the Swift Standard Libary.// Consider refactoring the code to use the non-optional operators.fileprivate func > <T : Comparable>(lhs: T?, rhs: T?) -> Bool {switch (lhs, rhs) {case let (l?, r?):return l > rdefault:return rhs < lhs}}
review时尽量确认具体情况,避免这种对比
如果去掉这两段'FIXME'代码,自动转换时会做如下转换:
(newText?.characters.count) > diagnosisMaxLength
到
(newText?.characters.count)! > diagnosisMaxLength
由于强制解包运行时不安全,所以应尽量避免这样转写,改为:
(newText?.characters.count ?? 0) > diagnosisMaxLength
当然前提是了解副作用,改写后的代码跟源代码有细微的不同,所以明确知道这段代码做什么,再做出合适的转写。
dispatch_async(dispatch_get_main_queue(), {self.setNeedsDisplay()})
会转换成
dispatch_get_main_queue().asynchronously(DispatchQueue.mainexecute: {self.setNeedsDisplay()})
实际上使用 swift 风格的 DispatchQueue 更合适
DispatchQueue.main.async(execute: {self.setNeedsDisplay()})
类似:
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0).asynchronously(DispatchQueue.globalexecute: reloadDataBlock)
应为
DispatchQueue.global(qos: .background).async(reloadDataBlock)
还有DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.default)中的GlobalQueuePriority已被废弃,可以改用DispatchQueue.global()(等价于DispatchQueue.global(qos: .default))
var header = MainViewHeader.instanceView()
MainViewHeader.instanceView声明的的返回值类型是MainViewHeader!,swift 2.3到3发生了变化。
header的类型在 swift 2 中为MainViewHeader!,而在 swift 3 中为 MainViewHeader?。
对于oc转换到swift的代码,这样做无疑更加安全,但是也成了在升级过程中不得不注意的细节,会报不少error,需要手动处理。
MRUser.shardedInstance()返回一个MRUser!,当使用自动类型推导时,swift 2跟3区别比较大
let MRUSER = MRUser.shardedInstance()
在swift2里 MRUSER 的类型是 MRUser!,而swift3里 MRUSER 的类型是 MRUser?,
这导致了一个很大的问题,就是在使用中,MRUSER需要开发者进行解包处理,如果仅仅使用编译器自动转换的代码,会发生不可预料的问题,例如
let userId = "\(MRUSER.getUserId())" // swift2let userId = "\(MRUSER?.getId())" // swift3
userId在 swift3 为 "Optional..." 形式,而在 swift2 为正常的。
改法暂时就是
let MRUSER: MRUser = MRUser.shardedInstance()
再根据编译器提示,改正其他部分的自动解包行为。
针对这一类型的问题,前者必须在自动转换后手动修正错误。
后者,可以以\(为关键字,筛选符合\(someValue)的代码,逐一查看是不是有相关问题,有则改之。
在OC中返回NSMutableDictionary的方法,转换器不能自主转换
FIXME
let dic = chartGroupModel.toDictionary() as NSDictionary as? [AnyHashable: Any] ?? [:]
一般在下面代码的MRMedicalRecordSyncSpecifyObjectKey处出现
guard let obj = notification?.object as? [NSObject: NSObject] else {return}let uid = obj[MRMedicalRecordSyncSpecifyObjectKey] as? String
这是因为 String 类型不匹配 NSObject,需要显式转换
guard let obj = notification?.object as? [NSObject: NSObject] else {return}let uid = obj[MRMedicalRecordSyncSpecifyObjectKey as NSObject] as? String
type 'MedicalRecordListViewModel' does not conform to protocol 'UIPickerViewDataSource'extension MedicalRecordListViewModel: UIPickerViewDataSource, UIPickerViewDelegate { ... }
在某些协议实现的 extension 里,转换器不会自动转换协议的方法名,这个例子里, swift 2 版本的 MedicalRecordListViewModel 实现了 UIPickerViewDataSource ,但是自动转换到 swift 3 后,方法的名字还是 swift 2 的,导致找不到对应的方法。
难办的是,如果该协议有required的方法,编译器会自动报出error,optional 的方法,就无能为力了,需要仔细排查。
相当多的方法参数类型中的AnyObject都变为了Any,这个也需要注意
//swift2func mralbumImagePickerViewController(_ mralbumImagePickerViewController: MRAlbumImagePickerViewController!, didFinishPickingMediaWithCameras filePaths: [AnyObject]!, photos: [AnyObject]!)//swift3func mralbumImagePickerViewController(_ mralbumImagePickerViewController: MRAlbumImagePickerViewController!, didFinishPickingMediaWithCameras filePaths: [Any]!, photos: [Any]!)
update: 针对部分delegate方法名没有转换的问题,好在swift代码里基本上都显式实现了delegate协议,不存在oc里明明实现了该协议但是却没有声明的情况,所以目前,采取的方案是排查所有实现了delegate的swift类,用正则过滤,逐一排查,表达式为(class|extension)\s[\w]+[\s]*:[\s\,\w]*(Delegate|DataSource|Protocol|Callback)
另外,因为强制加上了override关键字,继承应该不存在该问题。
//## Selector
dispatch_once(&Singleton.onceToken, {Singleton.single = ConversationVoiceManager()})return Singleton.single!
实际上在swift里不推荐这样写单例,应该这样
private static let sharedManager = ConversationVoiceManager()
CGFloat.max to CGFloat.greatestFiniteMagnitude
UIFont.systemFontOfSize(14) to UIFont.systemFont(ofSize: 14)