Swift3.0最大的變化妨马,有太多太多挺举,沒(méi)有最大,只有一樣大烘跺。
先前工程除了第三方庫(kù)湘纵,其余全部用Swift開(kāi)發(fā),也經(jīng)歷了2.1到2.2的遷移滤淳,2.2到2.3的遷移梧喷。在2.3版本時(shí),編譯器已經(jīng)有了一些警告脖咐,某些語(yǔ)法將在Swift3.0中不能再使用伤柄,比如參數(shù)中的var聲明,UIButton的構(gòu)造方法等等文搂。但讓人沒(méi)想到的是适刀,Swift3.0真正到來(lái)時(shí),更需要花費(fèi)我2天的時(shí)間埋頭改改改煤蹭。謹(jǐn)以此文笔喉,記錄遷移過(guò)程取视。
注意事項(xiàng)
手里兩個(gè)業(yè)務(wù)工程用Swift遷移工具,其中有一個(gè)因?yàn)镃ocoaPods的原因常挚,一直卡在Generating Preview的階段作谭。后來(lái)偶然因?yàn)镃ocoaPods由于GFW的原因不能執(zhí)行update命令更新第三方庫(kù),我把CocoaPods去掉了奄毡,第三方庫(kù)直接放主工程里折欠,恢復(fù)原始工程結(jié)構(gòu),就可以正常遷移了吼过。
自動(dòng)遷移部分
- 已經(jīng)聲明的枚舉值被全部改為首字母小寫(xiě)锐秦,因?yàn)樾乱?guī)范認(rèn)為枚舉相當(dāng)于類(lèi),值是成員盗忱,那么成員就應(yīng)當(dāng)以駝峰法命名酱床,首字母小寫(xiě);
- 已經(jīng)聲明的方法被拆分調(diào)用趟佃。比如autolayout的封裝庫(kù)PureLayout扇谣,設(shè)置布局的方法autoPinEdgeToSuperviewEdge()變成autoPinEdge(toSuperviewEdge:);諸如此類(lèi)還有很多闲昭,例如UIColor.whiteColor() -> UIColor.white......總之罐寨,盡可能的讓能推斷出類(lèi)型的情況,少寫(xiě)重復(fù)詞序矩。當(dāng)然鸯绿,還有變長(zhǎng)的方法名,例如view.hidden -> view.isHidden贮泞。
- 關(guān)于類(lèi)成員變量的權(quán)限楞慈,遷移工具默認(rèn)將先前的private權(quán)限改為fileprivate,因?yàn)樾乱?guī)范中的private就算在同文件中但不在同一個(gè)類(lèi)里也是無(wú)訪問(wèn)權(quán)限的啃擦。因此先前的private權(quán)限囊蓝,等同于現(xiàn)在的fileprivate。
- closure閉包現(xiàn)在有了更詳細(xì)的宏聲明了令蛉,聲明閉包是否會(huì)作為存儲(chǔ)型變量被強(qiáng)引用聚霜。因?yàn)閷?duì)閉包的強(qiáng)引用會(huì)導(dǎo)致外部對(duì)象一直不能被釋放,外部就需要使用weak var 來(lái)讓closure對(duì)傳入的對(duì)象只保持弱引用珠叔。不顯式聲明默認(rèn)是非存儲(chǔ)型閉包蝎宇,當(dāng)閉包被強(qiáng)引用則需要添加@escaping,位置在變量冒號(hào)后面祷安,類(lèi)型前面姥芥,例如
failureCallback: @escaping ((_ errorMsg: String) -> Void) - 方法聲明參數(shù)現(xiàn)在分三部分,冒號(hào)左邊一部分是標(biāo)簽汇鞭,另一部分是參數(shù)名凉唐,冒號(hào)右邊是變量類(lèi)型庸追。在Swift3.0以前,標(biāo)簽可有可無(wú)台囱,沒(méi)有標(biāo)簽時(shí)直接用變量名當(dāng)標(biāo)簽使用淡溯;Swift3.0規(guī)范了方法命名,規(guī)定必須使用標(biāo)簽簿训,如果強(qiáng)制不使用標(biāo)簽咱娶,那么方法聲明時(shí)標(biāo)簽用一根下劃線"_"替代。自動(dòng)遷移工具無(wú)法完成更詳細(xì)的識(shí)別强品,因此只能把大部分方法的標(biāo)簽先改為"_"膘侮。
手動(dòng)遷移部分
按照新規(guī)范,其實(shí)所有的方法命名都應(yīng)該重寫(xiě)择懂。自動(dòng)遷移讓大部分方法的參數(shù)標(biāo)簽喻喳,都變?yōu)榱?"另玖。這只是一個(gè)過(guò)渡的困曙,能讓程序快速通過(guò)編譯的方案,如果有足夠時(shí)間谦去,方法名最好規(guī)范起來(lái)慷丽。
例如
func reloadUIWithData( data: BaseData?) {}
新規(guī)范下,命名為:
func reloadUI(withData data: BaseData?) {}閉包作為參數(shù)聲明時(shí)鳄哭,標(biāo)簽只能用"_"要糊。調(diào)用閉包則不需要標(biāo)簽,直接寫(xiě)值妆丘,多個(gè)參數(shù)值用","分隔锄俄。
例如
func request(_ redPacketID: Int64,
successCallback: @escaping ((_ code: Int32, _ msg: String, _ rsp: RspLookRedPackage) -> Void),
failureCallback: @escaping ((_ errorMsg: String) -> Void)) {
}
調(diào)用時(shí),寫(xiě):
successCallback(rspMessage.rsp.retCode, rspMessage.rsp.retMsg, rspResult)-
Swift語(yǔ)言本身不支持同名方法重載勺拣,碰到需要重載的場(chǎng)景一般都是用不同數(shù)量參數(shù)奶赠,或不同的起始方法名來(lái)解決。如果第三方庫(kù)中的方法名药有,被Swift3.0拆分成了相同起始方法名相同參數(shù)數(shù)量的方法毅戈,則需要Objective-C文件做橋接。
SDWebImage庫(kù)中愤惰,為UIImage下載圖片有以下兩個(gè)方法:
- (void)sd_setImageWithURL:(NSURL *)url
placeholderImage:(UIImage *)placeholder
options:(SDWebImageOptions)options {}- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock { }
在Swift3.0中苇经,會(huì)被識(shí)別成
那么,在使用sd_setImage(with:....)時(shí)宦言,編譯器會(huì)報(bào)如下錯(cuò):
解決方法就是創(chuàng)建一個(gè)Objective-C類(lèi)別扇单,添加起始方法名不同的方法名。
//頭文件
#import <UIKit/UIKit.h>
#import <UIImageView+WebCache.h>
@interface UIImageView (SDWebImageSwiftBridge)
- (void)swiftBridge_sd_setImageWithURL:(NSURL *)url
placeholderImage:(UIImage *)placeholder
completed:(SDWebImageCompletionBlock)completedBlock;
@end
//實(shí)現(xiàn)文件
@implementation UIImageView (SDWebImageSwiftBridge)
- (void)swiftBridge_sd_setImageWithURL:(NSURL *)url
placeholderImage:(UIImage *)placeholder
completed:(SDWebImageCompletionBlock)completedBlock {
[self sd_setImageWithURL:url placeholderImage:placeholder completed:completedBlock];
}
@end
-
以上全部完成后奠旺,編譯運(yùn)行蜘澜,立即就發(fā)現(xiàn)了一個(gè)bug阻桅。比如聲明的String!類(lèi)型值,在用=賦值后兼都,類(lèi)型就變成了String?嫂沉。在Swift3.0以前,String!類(lèi)型的值傳遞或經(jīng)方法返回后扮碧,可以直接當(dāng)String類(lèi)型的用趟章。也就是說(shuō),如果現(xiàn)在String!需要傳遞或作為方法返回值慎王,要么強(qiáng)制解包成String再傳蚓土,要么不解包傳到別處就是String?。String?對(duì)象在被使用時(shí)赖淤,假如值是"123"蜀漆,那么它將會(huì)是Optional("123")樣式。比如拼接網(wǎng)址時(shí)咱旱,這樣網(wǎng)址的網(wǎng)頁(yè)就無(wú)法打開(kāi)确丢。
寫(xiě)了更多的Swift3.0代碼,發(fā)現(xiàn)了設(shè)計(jì)的根本所在吐限。在Swift3.0中鲜侥,所有聲明為Optional的類(lèi)型,直接打印的話都會(huì)被當(dāng)做非強(qiáng)制解包類(lèi)型诸典。比如下面代碼
因此,以往String!類(lèi)型對(duì)象打印值等同于String的情況狐粱,已經(jīng)變成了String!打印值等同于String?舀寓,為Optional("")
我想,這樣的變動(dòng)肌蜻,更多是出于嚴(yán)格區(qū)分普通類(lèi)型和可選類(lèi)型互墓,進(jìn)一步加強(qiáng)安全性的舉措。之前的版本里宋欺,如果一個(gè)方法的返回值是String!類(lèi)型轰豆,那么是可以直接當(dāng)String來(lái)用;而現(xiàn)在齿诞,方法返回類(lèi)型如果為String!酸休,獲取到的返回值實(shí)際上是String?〉昏荆客觀上說(shuō)斑司,String!的返回值也是可以為nil的,所以如果在外部直接使用獲取的返回值,為nil的情況會(huì)直接導(dǎo)致crash宿刮。尤其是老舊的OC代碼互站,沒(méi)有_Nonnull或_Nullable修飾的返回值,在Swift中全部默認(rèn)為強(qiáng)制解包類(lèi)型僵缺,現(xiàn)在都要當(dāng)?類(lèi)型用了胡桃。
String!目前和String?最大共同點(diǎn)在于,如果當(dāng)前值是Optional("123")磕潮,那么在使用該值是翠胰,將都是String?;另外自脯,它們的區(qū)別就是之景,調(diào)對(duì)象方法或訪問(wèn)對(duì)象屬性時(shí),String!會(huì)直接以解包對(duì)象的方式去調(diào)膏潮,而String?仍然是可選鏈方法锻狗。詳細(xì)見(jiàn)下圖