14年6月3日蘋果發(fā)布Swift以來潘明,這門語言以讓人驚訝的速度在成長虽另,越來越多的開發(fā)者關(guān)注學(xué)習(xí)丐巫,很多App和開源庫也在從Objective-C遷移到Swift上。
Swift語法確實更新進斤斧、更漂亮早抠,而在實際開發(fā)過程中,由于Objective-C更貼近底層撬讽,可以使用如OC Runtime這樣的黑魔法贝或,很多開源庫也是依賴其實現(xiàn)。因此OC和Swift混編應(yīng)該一個長期的趨勢锐秦,之前只是依賴于Xcode自動引入bridge header等類似的機制咪奖,沒有仔細去理解,借著新做項目用到evernote oc庫的機會好好的總結(jié)一下酱床。蘋果提供的Swift與Objective-C混編方案都是基于Xcode和LLVM編譯羊赵,采用Mix and Match機制。
從開發(fā)者實現(xiàn)角度根據(jù)不同的混編場景可以分為如下幾種情況:
普通代碼混編:項目內(nèi)普通代碼文件混編(.swift內(nèi)使用OC的.h和.m文件或者反過來扇谣,包括.a形式項目的開發(fā))昧捷,采用的bridge方案;
開發(fā)Framework混編:如果你的項目是輸出一個Framework罐寨,混編方式稍有不同靡挥,姑且成為umbrella方案;
引用外部Framework和宿主App混編:如果你的項目引用一個外部提供的Framework(無論這個Framework是單一語言開發(fā)還是本身就是混編的)鸯绿,混編方案也有不同跋破。> 詳細的原理參見上文提到的官方文檔簸淀,本文主要關(guān)注三種方式的實現(xiàn)以及可能遇到的問題。
普通代碼文件混編方案:
Swift引用OC實現(xiàn)通過橋接頭文件毒返,OC引用Swift實現(xiàn)直接importProductModuleName-Swift.h
這個文件即可租幕。
OC引用Swift實現(xiàn)
ProductModuleName
在Build Settings
里面配置:
默認用ProductName,可以支持自定義拧簸。(注明:Framework項目不支持自定義)
Swift引用OC實現(xiàn)
Swift引用OC實現(xiàn)稍微麻煩一點劲绪,需要自己生成一個bridge header文件,和創(chuàng)建普通.h方式相同File > New > File > (iOS, watchOS, tvOS, or OS X) > Source > Header File
盆赤,名字隨意贾富,然后配置到Build Settings - Swift Compiler - Code Generation
下的Objective-C Bridging Header
選項。
注意路徑從項目根目錄開始計算牺六,可以使用..
來指定與根目錄平級目錄颤枪。bridge header內(nèi)import所有想要在swift中使用的OC類,就會作為一個module在swift中使用兔乞。例如:
#import "XYZCustomCell.h"
#import "XYZCustomView.h"
#import "XYZCustomViewController.h"
Swift中用如下代碼訪問:
let myOtherCell = XYZCustomCell()
myOtherCell.subtitle = "Another custom cell"
FYI. 語言類型為Swift的項目引入OC文件時Xcode會給個創(chuàng)建bridge header的提示,自己會配置了之后用處不大:
Framework項目中使用代碼混編方案:
Umbrella Header的相關(guān)知識蘋果沒有給出很明確的說明凉唐,只有以前介紹Umbrella Framework的時候介紹過庸追,找了很久發(fā)現(xiàn)iOS - Umbrella Header在framework中的應(yīng)用這篇文章介紹的很好,詳細的內(nèi)容可以進入了解台囱。
Swift引用OC實現(xiàn)
現(xiàn)在我們只需要了解Framework里面Swift引用OC邏輯需要一個與ProductName同名的.h文件作為Umbrella Header淡溯,如果不存在則創(chuàng)建一個。不需要在Build Settings
配置因為這文件是map modules的時候自動指定的簿训,如果基于某種原因(比如這個同名文件已經(jīng)被用來寫其他邏輯)一定要自定義的話可以參考上面文章里介紹的方法咱娶。第二步到Build Settings - Packaging
中將Defines Module
選項設(shè)為YES
。然后將Swift中需要引用的OC邏輯引用進來强品,訪問方式同普通代碼混編膘侮。
#import "XYZCustomCell.h"
#import "XYZCustomView.h"
#import "XYZCustomViewController.h"
OC引用Swift
實現(xiàn)OC引用Swift同樣需要將Defines Module
選項設(shè)為YES
,其余和普通代碼混編相比只是改了個引用文件的方式:#import
的榛。
引用外部Framework時混編
方案:
重要前提
這里有一個重要的前提是這個外部Framework在編譯時必須開啟了Defines Module
琼了,如果沒有開啟并且沒有Framework源碼的情況下還是繞路吧。
external framework混編
在這種情況下當(dāng)前App使用外部Framework是不關(guān)心其內(nèi)部到底是Swift實現(xiàn)夫晌、OC實現(xiàn)還是本身就是混編實現(xiàn)的雕薪。只需要Swift使用Framework邏輯時添加import FrameworkName
,OC使用時在任意.m
文件中添加@import FrameworkName;
語法即可晓淀。
混編后哪些邏輯可以被另一種語言引用到所袁?
Swift中可以被OC引用的邏輯:
用
public
關(guān)鍵字;有bridging header的target中用
internal
關(guān)鍵字修飾凶掰;用
private
修飾的關(guān)鍵字通常是訪問不到的燥爷,除了@IBAction, @IBOutlet, 和 @objc標(biāo)記蜈亩;
OC中由于開發(fā)習(xí)慣的原因基本上頭文件中的屬性、方法都可以被swift訪問到局劲。
Evenote-Mac Framework混編時遇到的問題
-
Evenote-Mac
這個奇葩的Framework名字在生成umbrella header的時候報錯:
warning: EvernoteSDK-Mac is not a valid PRODUCT_NAME for use with framework targets enabling DEFINES_MODULE (name is not a valid C99 extended identifier)
warning: no umbrella header found for target 'EvernoteSDK-Mac', module map will not be generated
因為名字中有-
字符勺拣,所以只能替換或者去掉;
- 改名時建議直接改target的名字鱼填,只改module的名字就會報錯:
Warning: PRODUCT_MODULE_NAME may not be overridden for framework target 'EvernoteSDKMac'