本節包含內容: html
Mix and Match 概述(Mix and Match Overview) ios
在同個應用的 target 中導入(Importing Code from Within the Same App Target) swift
在同個 Framework 的 target 中導入(Importing Code from Within the Same Framework Target) app
導入外部 framework(Importing External Frameworks) 框架
在 Objective-C 中使用 Swift(Using Swift from Objective-C) ide
爲 Objective-C 接口重寫 Swift 名稱 函數
Product 模塊命名(Naming Your Product Module) 單元測試
問題解決提示(Troubleshooting Tips and Reminders) 測試
Swift 與 Objective-C 的兼容能力使你能夠在同一個工程中同時使用兩種語言。你能夠用這種叫作 mix and match 的特性來開發基於混合語言的應用,能夠用 Swift 的最新特性實現應用的一部分功能,並沒有縫地併入已有的 Objective-C 的代碼中。
Mix and Match 概述 ui
Objective-C 和 Swift 文件能夠在一個工程中並存,無論這個工程本來是基於 Objective-C 仍是 Swift。你能夠直接往現有工程中簡單地添加另外一種語言的源文件。這種天然的工做流使得建立混合語言的應用或框架 target,與用單獨一種語言時同樣簡單。
混合語言的工做流程只有一點點區別,這取決於你是在寫應用仍是寫框架。下面描述了普通的用兩種語言在一個 target 中導入模型的狀況,後續章節會有更多細節。
在同個應用的 target 中導入
若是你在寫混合語言的應用,可能須要用 Swift 代碼訪問 Objective-C 代碼,或者反之。下面的流程描述了在非框架 target 中的應用。
將 Objective-C 導入 Swift
在一個應用的 target 中導入一些 Objective-C 文件供 Swift 代碼使用時,你須要依賴於 Objective-C 的橋接頭文件(bridging header)來暴露給 Swift。當你添加 Swift 文件到現有的 Objective-C 應用(或反之)時,Xcode 會自動建立這些頭文件。
若是你贊成,Xcode 會在源文件建立的同時生成頭文件,並用 product 的模塊名加上 -Bridging-Header.h 命名。關於 product 的模塊名,詳見 Naming Your Product Module。
你應該編輯這個頭文件來對 Swift 暴露出 Objective-C 代碼。
在同一 target 中將 Objective-C 代碼導入到 Swift 中
1.在 Objective-C 橋接頭文件中,import任何你想暴露給 Swift 的頭文件,例如:
1
2
3
|
#import "XYZCustomCell.h"
#import "XYZCustomView.h"
#import "XYZCustomViewController.h"
|
2.確保在 Build Settings 中 Objective-C 橋接頭文件的 build setting 是基於 Swfit 編譯器,即 Code Generation 含有頭文件的路徑。這個路徑必須是頭文件自身的路徑,而不是它所在的目錄。
這個路徑應該是你工程的相對路徑,相似 Info.plist 在 Build Settings 中指定的路徑。在大多數狀況下,你不須要修改這個設置。
在這個橋接頭文件中列出的全部 public 的 Objective-C 頭文件都會對 Swift 可見。以後當前 target 的全部 Swift 文件均可以使用這些頭文件中的方法,不須要任何 import 語句。用 Swift 語法使用這些 Objective-C 代碼,就像使用系統自帶的 Swift 類同樣。
1
2
|
let myCell = XYZCustomCell()
myCell.subtitle = "A custom cell"
|
將 Swift 導入到 Objective-C
當你在將 Swift 代碼導入到 Objective-C 中時,你依賴於 Xcode 生成的頭文件來將這些文件暴漏給 Objective-C。這個自動生成的文件是一個 Objective-C 頭文件,它包含了你的 target 中全部 Swift 代碼中定義的接口。能夠把這個 Objective-C 頭文件看做 Swift 代碼的 umbrella header。頭文件名稱以 product 模塊名加 -Swift.h 來命名。(關於 product 的模塊名,詳見Naming Your Product Module)。
默認狀況下,生成的頭文件包含了標記有public修飾符的 Swift 聲明接口。它還包含那些打上,若是您的應用程序的目標有一個Objective-C的橋接頭內部修改。標有private修飾符聲明不會出如今所生成的報頭。私人聲明沒有接觸到Objective-C的,除非它們被明確標有@IBAction ,@IBOutlet,或@objc爲好。若是您的應用程序的目標是編譯測試啓用,單元測試目標能夠訪問任何聲明與內部修飾,彷彿他們與公衆修飾符經過預先@testable的產品模塊導入語句聲明。
你不須要作任何事情來生成這個頭文件,只須要將它導入到你的 Objective-C 代碼來使用它。注意這個頭文件中的 Swift 接口包含了它所使用到的全部 Objective-C 類型。若是你在 Swift 代碼中使用你本身的 Objective-C 類型,確保先將對應的 Objective-C 頭文件導入到你的 Swift 代碼中,而後纔將 Swift 自動生成的頭文件導入到 Objective-C .m 源文件中來訪問 Swift 代碼。
在同一 target 中將 Swift 代碼導入到 Objective-C 中
在相同 target 的 Objective-C .m 源文件中,用下面的語法來導入Swift 代碼:
1
|
#import "ProductModuleName-Swift.h"
|
target 中任何 Swift 文件將會對 Objective-C .m 源文件可見,包括這個 import 語句。關於在 Objective-C 代碼中使用 Swift 代碼,詳見 Using Swift from Objective-C。
在同個 Framework 的 target 中導入
若是你在寫一個混合語言的框架,可能會從 Swift 代碼訪問 Objective-C 代碼,或者反之。
將 Objective-C 導入 Swift
要將一些 Objective-C 文件導入到同個框架 target 的 Swift 代碼中去,你須要將這些文件導入到 Objective-C 的 umbrella header 來供框架使用。
在同一 framework 中將 Objective-C 代碼導入到 Swift 中
確保將框架 target 的 Build Settings > Packaging > Defines Module 設置爲 Yes。而後在你的 umbrella header 頭文件中導入你想暴露給 Swift 訪問的 Objective-C 頭文件,例如:
1
|
#import #import #import
|
Swift 將會看到全部你在 umbrella header 中公開暴露出來的頭文件,框架 target 中的全部 Swift 文件均可以訪問你 Objective-C 文件的內容,不須要任何 import 語句。
1
2
|
let myCell = XYZCustomCell()
myCell.subtitle = "A custom cell"
|
將 Swift 導入 Objective-C
要將一些 Swift 文件導入到同個框架的 target 的 Objective-C 代碼去,你不須要導入任何東西到 umbrella header 文件,而是將 Xcode 爲你的 Swift 代碼自動生成的頭文件導入到你的 Obj .m 源文件去,以便在 Objective-C 代碼中訪問 Swift 代碼。
在同一 framework 中將 Swift 代碼導入到 Objective-C 中
確保將框架 target 的 Build Settings > Packaging 中的 Defines Module 設置爲 Yes。用下面的語法將 Swift 代碼導入到同個框架 target 下的 Objective-C .m 源文件去。
1
2
|
// OBJECTIVE-C
#import
|
這個 import 語句所包含的 Swift 文件均可以被同個框架 target 下的 Objective-C .m 源文件訪問。關於在 Objective-C 代碼中使用 Swift 代碼,詳見 Using Swift from Objective-C。
導入外部 Framework
你能夠導入外部框架,無論這個框架是純 Objective-C,純 Swift,仍是混合語言的。import 外部框架的流程都是同樣的,無論這個框架是用一種語言寫的,仍是包含兩種語言。當你導入外部框架時,確保 Build Setting > Pakaging > Defines Module 設置爲 Yes。
用下面的語法將框架導入到不一樣 target 的 Swift 文件中:
1
|
import FrameworkName
|
用下面的語法將框架導入到不一樣 target 的 Objective-C .m 文件中:
1
|
@import FrameworkName;
|
在 Objective-C 中使用 Swift
當你將 Swift 代碼導入 Objective-C 以後,即可用常規的 Objective-C 語法來使用 Swift 類。
1
2
|
MySwiftClass *swiftObject = [[MySwiftClass alloc] init];
[swiftObject swiftMethod];
|
Swift 的類或協議必須用 @objc屬性來標記,以便在 Objective-C 中可訪問。這個 屬性告訴編譯器這塊 Swift 代碼能夠從 Objective-C 代碼中訪問。若是你的 Swift 類是 Objective-C 類的子類,編譯器會自動爲你添加 @objc。詳見 Swift Type Compatibility。
你能夠訪問在 Swift 類或協議中使用用@objc屬性標記的任何對象,只要該對象與 Objective-C 兼容。不包括如下 Swift 獨有的特性:
範型(Generics)
元組(Tuples)
Swift 中定義的枚舉不包括Int原始值類型(Enumerations defined in Swift without Int raw value type)
Swift 中定義的結構體(Structures defined in Swift)
Swift 中定義的頂層函數(Top-level functions defined in Swift)
Swift 中定義的全局變量(Global variables defined in Swift)
Swift 中定義的類型別名(Typealiases defined in Swift)
Swift風格可變參數(Swift-style variadics)
嵌套類型(Nested types)
柯里化函數(Curried functions)
例如,使用範型類型做爲參數,或者返回元組的方法將不能在 Objective-C 中使用。
注意 你不能在 Objective-C 繼承一個 Swift 類。
在 Objective-C 頭文件中引用 Swift 類
這樣前向聲明 Swift 類:
1
2
3
4
5
6
7
|
// OBJECTIVE-C
// MyObjective-CClass.h
@class MySwiftClass;
@interface MyObjective-CClass : NSObject
- (MySwiftClass *)returnSwiftObject;
/* ... */
@end
|
爲 Objective-C 接口重寫 Swift 名稱
Swift 編譯器自動的將 Objective-C 代碼做爲常規 Swift 代碼導入。它將 Objective-C 的類工廠方法做爲 Swift 構造器導入,以及將 Objective-C 的枚舉類型名稱截斷處理。
在你的代碼中也許存在不可以被自動處理的邊界狀況。若是你須要更改導入到 Swift 中的 Objective-C 方法,枚舉,或者可選 set 值,你可使用NS_SWIFT_NAME宏來自定義導入的聲明。
類工廠方法
若是 Swift 編譯器沒法識別類工廠方法,你可使用NS_SWIFT_NAME宏,來正確導入構造器的 Swift 簽名。例如:
1
|
+ (instancetype)recordWithRPM:(NSUInteger)RPM NS_SWIFT_NAME(init(RPM:));
|
若是 Swift 編譯器錯誤的將一個方法識別爲類工廠方法,你可使用NS_SWIFT_NAME宏,來正確導入構造器的 Swift 簽名。例如:
1
|
(id)recordWithQuality:(double)quality NS_SWIFT_NAME(record(quality:));
|
枚舉
默認狀況下,Swift 將枚舉值的名稱前綴作截斷來導入枚舉。若是要自定義枚舉值的名稱,你可使用NS_SWIFT_NAME宏來傳遞 Swift 枚舉值名稱。例如:
1
2
3
4
|
typedef NS_ENUM(NSInteger, ABCRecordSide) {
ABCRecordSideA,
ABCRecordSideB NS_SWIFT_NAME("FlipSide"),
};
|
Product 模塊命名
Xcode 爲 Swift 代碼生成的頭文件的名稱,以及 Xcode 建立的 Objective-C 橋接頭文件名稱,都是從你的 product 模塊名生成的。默認你的 product 模塊名和 product 名同樣。然而,若是你的 product 名有特殊字符(nonalphanumeric,非數字、字母的字符),例如點號,那麼它們會被下劃線(_)替換以後做爲你的 product 模塊名。若是 product 名以數字開頭,那麼第一個數字會用下劃線替換掉。
你能夠給 product 模塊名提供一個自定義的名稱,Xcode 會用這個名稱來命名橋接的和自動生成的頭文件。你只須要在修改在 build setting 中的 Product Module Name 便可。
問題解決提示
把 Swift 和 Objective-C 文件看做相同的代碼集合,並注意命名衝突。
若是你使用了框架,確保在Packaging下的Defines Module編譯設置被設置爲 Yes。
若是你使用了 Objective-C 橋接頭文件,確保 Swift 編譯器中 Objective-C 橋接頭文件的編譯設置Code Generation有一個與項目相關的頭文件的路徑。這個路徑必須是頭文件自身的路徑,而不是它所在的目錄。
Xcode 使用你的工程模塊名,而不是以target的名稱來命名 Objective-C 橋接頭文件以及爲 Swift 代碼 自動生成的頭文件。詳見 Naming Your Product Module。
爲了在 Objective-C 中可用, Swift 類必須是 Objective-C 類的子類,或者用 @objc 標記。
當你將 Swift 導入到 Objective-C 中時,記住 Objective-C 不會將 Swift 獨有的特性轉化成 Objective-C 對應的特性。詳見列表 Using Swift from Objective-C。
若是你在 Swift 代碼中使用你本身的 Objective-C 類型,確保先將對應的 Objective-C 頭文件導入到你的 Swift 代碼中,而後纔將 Swift 自動生成的頭文件導入到 Objective-C .m 源文件中來訪問 Swift 代碼。
用private修飾符標記的 Swift 聲明不會出如今自動生成的頭文件中。私有聲明不會暴漏給 Objective-C,除非它們被明確標記有@IBAction,@IBOutlet或者@objc等。
對於應用 targets 而言,若是有 Objective-C 橋接頭文件時,被internal修飾符標記的聲明會出如今自動產生的頭文件中。
對於框架 targets 而言,只有被public修飾符標記的聲明纔會出如今自動生成的頭文件中。你仍然能夠在框架中的 Objective-C 部分使用被internal修飾符標記的 Swift 方法和屬性,只要它們聲明所在的類繼承自 Objective-C 類。關於訪問級別修飾符的更多信息,請查看The Swift Programming Language中的訪問控制(Access Control)