同一個項目中使用Swift和Objective-C

在同一個項目中使用Swift 和 Objective-C

原創翻譯,轉載註明

原文鏈接:原文

Swift 對Objective-C 的兼容性允許你創建一個包含這兩種語言文件的工程。你可以使用名爲:“mix and match”的特性來編寫包含混合語言代碼的app。使用”mix and match”,你可以使用swift的新特性來編寫app一部分的功能,同時無縫的和現有的Objective-C(下文簡稱OC) 代碼相融合。

Mix and Match 概述

OC和swift代碼可以在一個工程中共存,無論這個工程原本是OC還是swift工程。你可以輕易的在已有工程文件中添加另一種語言文件。對於創建混合語言的app或framework 來說,這種自然的工作方式和使用單種語言一樣直截了當。

寫混合語言的流程取決於你是寫app還是framework,情況略微不同。對於同一個target要想用兩種語言混寫,大體的工作流程如下圖所繪,具體的內容會在後面的章節描述。

在同一個app Target裏進行語言代碼導入

如果你在寫一個混合語言的app,你應該需要在OC中訪問swift代碼或者從swift中訪問OC代碼。這個流程會在本章節描述,但僅僅適用於非framework的targets。

把OC代碼導入爲Swift可用

要在同一個target中導入一些OC文件能爲Swift所用,你要依靠”Objective-C bridging header”這個特性來保證OC文件對swift來說是可見的.當你在一個OC項目中添加一個swift文件或者在swift項目中添加OC文件,Xcode會創建頭文件來保證兩者的可互訪性。

當點擊同意的時候,xcode會在你創建OC文件時同時創建一個頭文件,它是根據你工程的product module name加上”-Bridging-Header.h” 拼接而成的。關於product module name的更多信息,後面章節會提到。

在同一個 app target中把OC代碼導入爲Swift

1.在你的Objective-C bridging header文件中,把所有你想暴露給swift 的頭文件寫在裏面,例如:

1
2
3
4
5
OBJECTIVE-C

#import "XYZCustomCell.h"
#import "XYZCustomView.h"
#import "XYZCustomViewController.h"

2.在Build Settings裏,確保項目Swift Compiler – Code Generation中 Objective-C Bridging Header指向了你的Bridging Header文件,這個path指向的是你的Bridging Header文件,而不是它所在的目錄

這個path應該是相對路徑,和Build Settings定義的 Info.plist一樣。大部分情況下你不需要修改這個配置

任何一個在 bridging header 文件中列出來的OC頭文件對swift來說都是可見的。在這個target裏 OC代碼的功能對任何一個swift文件都是自動可用的,不需要導入任何聲明。你可以像使用系統classes一樣來使用你自定義的OC代碼了。

1
2
3
4
5

SWIFT

let myCell = XYZCustomCell()
myCell.subtitle = "A custom cell"

把Swift代碼導入爲OC可用

當你想讓Swift代碼導入爲OC可用時,你要依賴Xcode-generated header 這個文件去向OC暴露接口。這個自動生成的文件是一個OC的頭文件,其中聲明瞭項目中所有Swift代碼的接口。它可以理解爲Swift代碼的傘頭(umbrella header)。這個文件的命名是以你的product module name加上”-Swift.h” 拼接而成的,關於product module name的更多信息,後面章節會提到。

你不需要做任何額外事情來創建這個文件,你只需要在你們的OC代碼中import,然後使用就好了。注意,swift代碼中使用的所有OC代碼也會被generated header中的Swift接口所引用。如果你在SWift代碼中使用le 自己的OC代碼(譯者注:非系統class),那麼你必須在OC的.m文件中先導入swift代碼中引入OC的OC頭文件,然後纔可以導入Swift generated header來訪問swift代碼。(譯者注:簡單的就是說在Objective-C bridging header中聲明的頭文件讓你可以在swift中訪問OC代碼,當你在OC中訪問swift代碼時候,必須在導入generated header之前先導入這些OC頭文件。基於這點,要想在預編譯pch文件中導入generated header是不現實的,貌似Xcode6以後pch已經被幹掉了)

在同一個app target中將Swift代碼導入爲OC可用

在同一個target中,將以合適名稱命名的Swift代碼接口文件(generated header)導入到任何需要用到swift代碼的OC.m文件中

1
2
3
OBJECTIVE-C

#import “ProductModuleName-Swift.h”

在任何導入這個聲明頭文件的地方,Swift代碼都是可見的。

在同一個Framework target裏進行語言代碼導入

如果你在寫一個混合語言的framework,你應該需要在OC中訪問swift代碼或者從swift中訪問OC代碼。

把OC代碼導入爲Swift可用

要在同一個 framework target中導入一些OC文件能爲Swift所用,你需要在 Objective-C umbrella header中導入這些OC的頭文件

在同一個 framework target中把OC代碼導入爲Swift 可用

1.在Build Settings-Packaging中,確保 Defines Module setting被設置爲YES 2.在你的umbrella header file中,和app target一樣,導入你想要暴露給swift的頭文件。例如:

1
2
3
4
5
OBJECTIVE-C

#import "XYZCustomCell.h"
#import "XYZCustomView.h"
#import "XYZCustomViewController.h"

任何一個在 umbrella header 文件中列出來的OC頭文件對swift來說都是可見的。在這個target裏 OC代碼的功能對任何一個swift文件都是自動可用的,不需要導入任何聲明。你可以像是使用系統classes一樣來使用你自定義的OC代碼了。

1
2
3
4
SWIFT

let myCell = XYZCustomCell()
myCell.subtitle = "A custom cell"

把swift代碼導入爲OC可用

當你要想讓Swift代碼導入爲OC可用,你不需要在 umbrella header 中導入任何東西。和app target類似,你只需要在需要用到swift代碼的OC .m文件中導入 Xcode-generated header 文件就好了

在同一個 framework target中把swift代碼導入爲OC可用

1.在Build Settings-Packaging中,確保 Defines Module setting被設置爲YES 2.在同一個target中,將以合適名稱命名的Swift代碼接口文件(generated header)導入到任何需要用到的OC .m文件中

1
2
3
OBJECTIVE-C

#import “ProductModuleName-Swift.h”

在任何導入這個聲明頭文件的地方,Swift代碼都是可見的。

導入外部Frameworks

你可以導入完全使用OC、swift或者混合代碼編寫的外部frameworks。使用這些frameworks的方法是一樣的,無論其是單一語言編寫還是混合編寫的。當你導入一個外部framework,請確保你的項目Defines Module build setting被設置爲Yes。

你可以在不同target中導入一個framework到swift文件中:

1
2
3
SWIFT

import FrameworkName

你可以在不同target中導入一個framework到OC的.m文件中:

1
2
3
OBJECTIVE-C

@import FrameworkName

在OC中使用Swift

當你導入swift代碼到OC中時候,使用OC的常規語法就可以調用swift的classes了

1
2
3
4
OBJECTIVE-C

MySwiftClass *swiftObject = [[MySwiftClass alloc] init];
[swiftObject swiftMethod];

一個Swift class 或者 protocol 必須使用@objc的屬性標記纔可以被OC使用。這個屬性告訴編譯器這段swift代碼可以被OC所訪問到。如果你的swift class 是由 Objective-C class 派生的,那麼編譯器會自動幫你加上@objc標識,獲取更多信息請訪問:Swift Type Compatibility

當一個class或者protocol 被有@objc 屬性標識的時候,你可以訪問這個class或者protocol 裏面所有的東西,因爲它跟OC是兼容的。這裏有一些不兼容的特性列表(Swift-only):

  • Generics
  • Tuples
  • Enumerations defined in Swift
  • Structures defined in Swift
  • Top-level functions defined in Swift
  • Global variables defined in Swift
  • Typealiases defined in Swift
  • Swift-style variadics
  • Nested types
  • Curried functions

比如,一個方法有一個generic類型的參數或者返回值是個tuple類型,那它是不能被OC所用的

爲了避免循環引用,不要在一個OC的頭文件中導入swift。相反,你可以直接在OC的頭文件中聲明和使用swift class。然而要注意你不能在OC去子類化swift.

在OC的頭文件中引用一個Swift class

  • 直接聲明和使用
1
2
3
4
5
6
7
8
OBJECTIVE-C

@class MySwiftClass;
 
@interface MyObjcClass : NSObject
 - (MySwiftClass *)returnSwiftObject;
/* ... */
@end

給 Product Module 命名

Xcode-generated header和 Objective-C bridging header 的命名都是由product module name得來的。默認情況下 product module name和product name是一樣的。然而如果你的 product name包含非字母數字字符,例如點(.),他們會被下劃線(_)取代。如果你的product name是以數字開頭,那麼首字符的數據也會被下劃線取代。

你同樣可以自定義你的product module name。Xcode會使用你改過的name來命名 bridging 和 generated headers。你可以在build setting裏面進行修改。

問題建議和提醒

  • 將你的Swift和OC文件放在同一個集合裏,當心命名衝突
  • 如果你開發frameworks,確保Packaging中的Defines Module被設置爲YES
  • 如果你使用到Objective-C bridging header,確保,確保項目Swift Compiler – Code Generation中 Objective-C Bridging Header指向了你的Bridging Header文件,這個path指向的是你的Bridging Header文件,而不是它的目錄
  • Xcode使用 product module name而不是 target name來命名bridging header and the generated header.更多信息參考上文”給 Product Module 命名”章節。
  • 一個 swift class 必須由OC class派生或者被@objc標識 才能被OC所獲取和使用
  • 當你在OC中使用Swift,記住OC並不能讀懂swift的一些特性,參考上文中的列表
  • 如果你在SWift代碼中使用自己的OC代碼,那麼你必須在OC的.m文件中先導入swift代碼中引入OC的OC頭文件,然後纔可以導入Swift
發佈了12 篇原創文章 · 獲贊 3 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章