Objective-C 與 Swift 混編教學

Tom Tung
8 min readAug 30, 2021

--

Photo by
Daniele Levis Pelusi on Unsplash

#前言

最近開始工作,公司專案本身是以 objective-C 開發,想慢慢轉型成 Swift,因此需要在 objective-C 專案中加入 Swift,而在嘗試的過程中也發生了一些小問題,今天就來看下混編可能會遇到的種種事吧。

#介紹

混編無非就是兩種情況:

  1. 在 objective-C 中調用 Swift
  2. 在 Swift 中調用 objective-C

在這過程中有兩個關鍵的文件:

  1. 橋接文件:”ProjectName-Bridging-Header.h”
  2. Objective-C Generated Interface Header Name 文件:”ProductModuleName-Swift.h”

#主要文件

橋接文件

  • 用途:Swift 調用 Objective-C Class 時使用,可以暴露 Objective-C files 給 Swift
  • 用法:在裡頭 #import “xxx.h”,Swift 即可使用
  • 如何叫出:當在 Objective-C app 中加入 Swift file 或者在 Swift app 中加入 Objective-C file,Xcode 就會提供創建
Photo by Apple Documentation

Objective-C Generated Interface Header Name 文件

  • 用途:Objective-C 調用 Swift Class 時使用,該 file 是一個 Objective-C header,用來聲明 Swift interfaces,可以當作是 Swift code 的 umbrella header
  • 用法:在想導入 Swift 的 Objective-C Class 中 #import “ProductModuleName-Swift.h” ,即可使用 Swift
  • 如何叫出:同 橋接文件
Photo by Apple Documentation

#實作

自動創建 Bridging Header

在 OC Project 中創建 Swift Class 會跳出視窗,如下:

Photo by Apple Documentation

點選 Create Bridging Header 會產生 ProjectName-Bridging-Header.h ,只有第一次生成 Swift Class 會出現。

同時在 Build Settings 裡會產生 Swift Compiler 配置:

如果點了 Don't Create ,將不會產生 OC Practice-Bridging-Header.hSwift Compiler 也不會有 Header Nam ,需要自行創建並配好路徑。

注意:確認 Info.plist 的路徑名稱跟 Bridging Header 是否一致的,大多情況下是相同的。

手動創建 Bridging Header

  1. 加入 header file:File >New > File > (Source) Header File. 檔案名稱通常設成 ProjectName-Bridging-Header.
    然後 create,不需要勾選任何的 target。
  2. 之後到 Target > Build Settings 尋找 Swift Compiler — General. 裡頭有 Objective-C Bridging Header 然後設置路徑,如果路徑不會設置可以參考可能遇到的問題

在 Objective-C 中調用 Swift

  1. Swift Class 的 property 和 function 需在前面加上 @objc ,Objective-C 才能抓到

注意!! Class 一定要有繼承,不然 Objective-C 會抓不到

2. 在任何 Objective-C .m file 中要先 #import “ProductModuleName-Swift.h”

3. 最後就可以在 Objective-C 中使用 Swift Class

用 private 或 fileprivate 修飾的聲明將不會出現在 generated header,並且不會在 Objective-C runtime 時暴露,除非帶有 @IBAction, @IBOutlet, or @objc 屬性。

在 Swift 中調用 Objective-C

  1. ProjectName-Bridging-Header.h 裡 import Swift 要調用的 Objective-C class

2. Swift 可以直接使用 import 的 Objective-C class

Swift 調用就簡單很多。

#可能遇到的問題

找不到 Swift Compiler

這意味著這 Project 還沒有 Swift file。在新增時記得所有 target 都要點選,不然會有 Swift 檔案有些 target 不能用的問題。

手動新增 Bridging Header 找不到位置

位置必須從有 .xcodeproj 這一層開始算起,如下圖

當有多個 targets,該如果處理 import “TargetName-Swift.h”

每個 target都有屬於自己的 Interface Header Name,不可能每換一個target就重打一次import,但又不能一口氣 import 所有 Interface Header Name ,除了當前 target 的 Interface Header Name 外,其他都會報錯。

解決方法:統一 Interface Header Name 的名稱

$(SWIFT_MODULE_NAME)-Swift.h 改成 $(PROJECT_NAME)-Swift.h

project 是同一個,因此不同 target 會有相同的 Interface Header Name

參考:
https://bmnotes.com/2018/04/19/quick-notes-swift-classes-into-objective-c-code-when-you-have-multiple-targets/

https://stackoverflow.com/questions/26262029/objective-c-to-swift-header-file-with-multiple-targets

#補充

ProductModuleName-Swift.h 究竟是什麼呢?

ProductModuleName-Swift.h 是一個自動生成的頭文件,沒有對應的 code,可以試著 Commend+LeftClick 進去看裡頭。

在 Swift Class 中加入的 property 和 function,都在OC_Practice-Swift.h 產生對應的OC 接口,因此可以通過 OC_Practice-Swift.h 去調用這些接口。

注意!!如果 Swift 的 property 和 function 前面沒有加上 @objc 就不會產生接口,因此 Objective-C 會抓不到。

--

--

Tom Tung

Hi, I’m Tom. I work as an iOS developer.