Swift 與 Objective-C 的兼容能力使你可以在同一個工程中同時使用兩種語言弃榨。你可以用這種叫做 mix and match 的特性來開發(fā)基于混合語言的應(yīng)用,可以用 Swfit 的最新特性實(shí)現(xiàn)應(yīng)用的一部分功能梨睁,并無縫地并入已有的 Objective-C 的代碼中鲸睛。
Mix and Match 概述
Objective-C 和 Swift 文件可以在一個工程中并存,不管這個工程原本是基于 Objective-C 還是 Swift坡贺。你可以直接往現(xiàn)有工程中簡單地添加另一種語言的源文件官辈。這種自然的工作流使得創(chuàng)建混合語言的應(yīng)用或框架 target,與用單獨(dú)一種語言時一樣簡單遍坟。
混合語言的工作流程只有一點(diǎn)點(diǎn)區(qū)別拳亿,這取決于你是在寫應(yīng)用還是寫框架。下面描述了普通的用兩種語言在一個 target 中導(dǎo)入模型的情況愿伴,后續(xù)章節(jié)會有更多細(xì)節(jié)肺魁。
在同個應(yīng)用的 target 中導(dǎo)入
如果你在寫混合語言的應(yīng)用,可能需要用 Swift 代碼訪問 Objective-C 代碼隔节,或者反之鹅经。下面的流程描述了在非框架 target 中的應(yīng)用寂呛。
將 Objective-C 導(dǎo)入 Swift
在一個應(yīng)用的 target 中導(dǎo)入一些 Objective-C 文件供 Swift 代碼使用時,你需要依賴與 Objective-C 的橋接頭文件(bridging header)來暴露給 Swift瘾晃。當(dāng)你添加 Swift 文件到現(xiàn)有的 Objective-C 應(yīng)用(或反之)時贷痪,Xcode 會自動創(chuàng)建這些頭文件。
如果你同意酗捌,Xcode 會在源文件創(chuàng)建的同時生成頭文件呢诬,并用 product 的模塊名加上 -Bridging-Header.h 命名。關(guān)于 product 的模塊名胖缤,詳見 Naming Your Product Module。
你應(yīng)該編輯這個頭文件來對 Swift 暴露出 Objective-C 代碼阀圾。
作為一個開發(fā)者哪廓,有一個學(xué)習(xí)的氛圍跟一個交流圈子特別重要,這是一個我的iOS開發(fā)交流群:130 595 548初烘,不管你是小白還是大牛都?xì)g迎入駐 涡真,讓我們一起進(jìn)步,共同發(fā)展I隹稹(群內(nèi)會免費(fèi)提供一些群主收藏的免費(fèi)學(xué)習(xí)書籍資料以及整理好的幾百道面試題和答案文檔6吡稀)
在同一 target 中將 Objective-C 代碼導(dǎo)入到 Swift 中
- 在 Objective-C 橋接頭文件中,import 任何你想暴露給 Swift 的頭文件吗铐,例如:
1. // OBJECTIVE-C
3. #import "XYZCustomCell.h"
4. #import "XYZCustomView.h"
5. #import "XYZCustomViewController.h"
- 確保在 Build Settings 中 Objective-C 橋接頭文件的 build setting 是基于 Swfit 編譯器东亦,即 Code Generation 含有頭文件的路徑。這個路徑必須是頭文件自身的路徑唬渗,而不是它所在的目錄典阵。
這個路徑應(yīng)該是你工程的相對路徑,類似 Info.plist 在 Build Settings 中指定的路徑镊逝。在大多數(shù)情況下壮啊,你不需要修改這個設(shè)置。
在這個橋接頭文件中列出的所有 public 的 Objective-C 頭文件都會對 Swift 可見撑蒜。之后當(dāng)前 target 的所有 Swift 文件都可以使用這些頭文件中的方法歹啼,不需要任何 import 語句。用 Swift 語法使用這些 Objective-C 代碼座菠,就像使用系統(tǒng)自帶的 Swift 類一樣狸眼。
1. // SWIFT
3. let myCell = XYZCustomCell()
4. myCell.subtitle = "A custom cell"
將 Swift 導(dǎo)入 Objective-C
向 Objective-C 中導(dǎo)入Swift 代碼時,你依賴 Xcode 生成的頭文件來向 Objective-C 暴露 Swift 代碼辈灼。這是自動生成 Objective-C 頭文件份企,它包含了你的 target 中所有 Swift 代碼中定義的接口⊙灿ǎ可以把這個 Objective-C 頭文件看作 Swift 代碼的 umbrella header司志。它以 product 模塊名加 -Swift.h 來命名甜紫。關(guān)于 product 的模塊名,詳見Naming Your Product Module骂远。
你不需要做任何事情來生成這個頭文件囚霸,只需要將它導(dǎo)入到你的 Objective-C 代碼來使用它。注意這個頭文件中的 Swift 接口包含了它所使用到的所有 Objective-C 類型激才。如果你在 Swift 代碼中使用你自己的 Objective-C 類型拓型,確保先將對應(yīng)的 Objective-C 頭文件導(dǎo)入到你的 Swift 代碼中,然后才將 Swift 自動生成的頭文件導(dǎo)入到 Objective-C .m 源文件中來訪問 Swift 代碼瘸恼。
在同一 target 中將 Swift 代碼導(dǎo)入到 Objective-C 中
在相同 target 的 Objective-C .m 源文件中劣挫,用下面的語法來導(dǎo)入Swift 代碼:
1. // OBJECTIVE-C
2. #import "ProductModuleName-Swift.h"
target 中任何 Swift 文件將會對 Objective-C .m 源文件可見,包括這個 import 語句东帅。關(guān)于在 Objective-C 代碼中使用 Swift 代碼压固,詳見 Using Swift from Objective-C。
導(dǎo)入到 Swift | 導(dǎo)入到 Swift | |
---|---|---|
Swift 代碼 | 不需要import語句 | #import |
Objective-C 代碼 | 不需要import語句靠闭;需要 Objective-C `umbrella頭文件 | #import "Header.h" |
在同個 Framework 的 target 中導(dǎo)入
如果你在寫一個混合語言的框架帐我,可能會從 Swift 代碼訪問 Objective-C 代碼,或者反之愧膀。
將 Objective-C 導(dǎo)入 Swift
要將一些 Objective-C 文件導(dǎo)入到同個框架 target 的 Swift 代碼中去拦键,你需要將這些文件導(dǎo)入到 Objective-C 的 umbrella header來供框架使用。
在同一 framework 中將 Objective-C 代碼導(dǎo)入到 Swift 中
確保將框架 target 的 Build Settings > Packaging > Defines Module 設(shè)置為 Yes檩淋。然后在你的 umbrella header 頭文件中導(dǎo)入你想暴露給 Swift 訪問的 Objective-C 頭文件芬为,例如:
1. // OBJECTIVE-C
2. #import <XYZ/XYZCustomCell.h>
3. #import <XYZ/XYZCustomView.h>
4. #import <XYZ/XYZCustomViewController.h>
Swift 將會看到所有你在 umbrella header 中公開暴露出來的頭文件,框架 target 中的所有 Swift 文件都可以訪問你 Objective-C 文件的內(nèi)容狼钮,不需要任何 import 語句碳柱。
1. // SWIFT
2. let myCell = XYZCustomCell()
3. myCell.subtitle = "A custom cell"
將 Swift 導(dǎo)入 Objective-C
要將一些 Swift 文件導(dǎo)入到同個框架的 target 的 Objective-C 代碼去,你不需要導(dǎo)入任何東西到 umbrella header 文件熬芜,而是將 Xcode 為你的 Swift 代碼自動生成的頭文件導(dǎo)入到你的 Obj .m 源文件去莲镣,以便在 Objective-C 代碼中訪問 Swift 代碼。
在同一 framework 中將 Swift 代碼導(dǎo)入到 Objective-C 中
確保將框架 target 的 Build Settings > Packaging 中的 Defines Module 設(shè)置為 Yes涎拉。用下面的語法將 Swift 代碼導(dǎo)入到同個框架 target 下的 Objective-C .m 源文件去瑞侮。
1. // OBJECTIVE-C
2. #import <ProductName/ProductModuleName-Swift.h>
這個 import 語句所包含的 Swift 文件都可以被同個框架 target 下的 Objective-C .m 源文件訪問。關(guān)于在 Objective-C 代碼中使用 Swift 代碼鼓拧,詳見 Using Swift from Objective-C半火。
導(dǎo)入到 Swift | 導(dǎo)入到 Swift | |
---|---|---|
Swift 代碼 | 不需要import語句 | #import |
Objective-C 代碼 | 不需要import語句;需要 Objective-C `umbrella頭文件 | #import "Header.h" |
導(dǎo)入外部 Framework
你可以導(dǎo)入外部框架季俩,不管這個框架是純 Objective-C钮糖,純 Swift,還是混合語言的。import 外部框架的流程都是一樣的店归,不管這個框架是用一種語言寫的阎抒,還是包含兩種語言。當(dāng)你導(dǎo)入外部框架時消痛,確保 Build Setting > Pakaging > Defines Module 設(shè)置為Yes且叁。
用下面的語法將框架導(dǎo)入到不同 target 的 Swift 文件中:
1. // SWIFT
2. import FrameworkName
用下面的語法將框架導(dǎo)入到不同 target 的 Objective-C .m 文件中:
1. // OBJECTIVE-C
2. @import FrameworkName;
導(dǎo)入到 Swift | 導(dǎo)入到 Objective-C | |
---|---|---|
任意語言框架 | import FrameworkName | @import FrameworkName; |
在 Objective-C 中使用 Swift
當(dāng)你將 Swift 代碼導(dǎo)入 Objective-C 文件之后,用普通的 Objective-C 語法使用 Swift 類秩伞。
1. // OBJECTIVE-C
3. MySwiftClass *swiftObject = [[MySwiftClass alloc] init];
4. [swiftObject swiftMethod];
Swift 的類或協(xié)議必須用 @Objective-C attribute 來標(biāo)記逞带,以便在 Objective-C 中可訪問。這個 attribute 告訴編譯器這個 Swift 代碼可以從 Objective-C 代碼中訪問纱新。如果你的 Swift 類是 Objective-C 類的子類展氓,編譯器會自動為你添加 @Objective-C attribute。詳見 Swift Type Compatibility怒炸。
你可以訪問 Swift 類或協(xié)議中用 @Objective-C attribute 標(biāo)記過東西带饱,只要它和 Objective-C 兼容。不包括一下這些 Swift 獨(dú)有的特性:
- Generics - 范型
- Tuples - 元組
- Enumerations defined in Swift - Swift 中定義的枚舉
- Structures defined in Swift - Swift 中定義的結(jié)構(gòu)體
- Top-level functions defined in Swift - Swift Swift 中定義的頂層函數(shù)
- Global variables defined in Swift - Swift 中定義的全局變量
- Typealiases defined in Swift - Swift 中定義的類型別名
- Swift-style variadics - Swift風(fēng)格可變參數(shù)
- Nested types - 嵌套類型
- Curried functions - 柯里化后的函數(shù)
例如帶有范型類型作為參數(shù)阅羹,或者返回元組的方法不能在 Objective-C 中使用。
為了避免循環(huán)引用教寂,不要將 Swift 代碼導(dǎo)入到 Objective-C 頭文件中捏鱼。但是你可以在 Objective-C 頭文件中前向聲明(forward declare)一個 Swift 類來使用它,然而,注意不能在 Objective-C 中繼承一個 Swift 類。
在 Objective-C 頭文件中引用 Swift 類
這樣前向聲明 Swift 類:
1. // OBJECTIVE-C
2. // MyObjective-CClass.h
4. @class MySwiftClass;
6. @interface MyObjective-CClass : NSObject
7. - (MySwiftClass *)returnSwiftObject;
8. /* ... */
9. @end
Product 模塊命名
Xcode 為 Swift 代碼生成的頭文件的名稱猾骡,以及 Xcode 創(chuàng)建的 Objective-C 橋接頭文件名稱翅阵,都是從你的 product 模塊名生成的。默認(rèn)你的 product 模塊名和 product 名一樣淑倾。然而,如果你的 product 名有特殊字符(nonalphanumeric,非數(shù)字藏斩、字母的字符),例如點(diǎn)號却盘,那么它們會被下劃線(_)替換之后作為你的 product 模塊名狰域。如果 product 名以數(shù)字開頭,那么第一個數(shù)字會用下劃線替換掉黄橘。
你可以給 product 模塊名提供一個自定義的名稱兆览,Xcode 會用這個名稱來命名橋接的和自動生成的頭文件。你只需要在修改在build setting 中的 Product Module Name 即可塞关。
問題解決提示
- 把 Swift 和 Objective-C 文件看作相同的代碼集合抬探,并注意命名沖突;
- 如果你用框架帆赢,確保 Build Setting > Pakaging > Defines Module 設(shè)置為 Yes小压;
- 如果你使用 Objective-C 橋接頭文件线梗,確保在 Build Settings 中 Objective-C 橋接頭文件的 build setting 是基于 Swfit 編譯器,即 Code Generation 含有頭文件的路徑场航。這個路徑必須是頭文件自身的路徑缠导,而不是它所在的目錄;
- Xcode 使用你的 product 模塊名溉痢,而不是 target 名來命名 Objective-C 橋接頭文件和為 Swift 自動生成的頭文件僻造。詳見 Naming Your Product Module;
- 為了在 Objective-C 中可用孩饼, Swift 類必須是 Objective-C 類的子類髓削,或者用 @Objective-C 標(biāo)記;
- 當(dāng)你將 Swift 導(dǎo)入到 Objective-C 中時镀娶,記住 Objective-C 不會將 Swift 獨(dú)有的特性翻譯成 Objective-C 對應(yīng)的特性立膛。詳見列表Using Swift from Objective-C;
- 如果你在 Swift 代碼中使用你自己的 Objective-C 類型梯码,確保先將對應(yīng)的 Objective-C 頭文件導(dǎo)入到你的 Swift 代碼中宝泵,然后才將 Swift 自動生成的頭文件 import 到 Objective-C .m 源文件中來訪問 Swift 代碼。