@wrlqwe
2017-02-06T06:49:27.000000Z
字数 5477
阅读 1282
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 candidate
open 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 candidate
open 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) in
self?.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) in
self?.showFormAffix(affixModel)
}, longPressAction: nil)
如果代码里用到了类似以下的特性:
var l = 10
var r: Int? = 5
let 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 < r
case (nil, _?):
return true
default:
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 > r
default:
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())" // swift2
let 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
,这个也需要注意
//swift2
func mralbumImagePickerViewController(_ mralbumImagePickerViewController: MRAlbumImagePickerViewController!, didFinishPickingMediaWithCameras filePaths: [AnyObject]!, photos: [AnyObject]!)
//swift3
func 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)