Swift 調(diào)用 OC 實(shí)用技巧

Swift App

混入OC/C/C++代碼

方法一

使用橋接文件。

方法二

使用.modulemap

  1. Swift App項(xiàng)目,引入OC/C/C++文件。
  2. 創(chuàng)建文件名必須為module 后綴為.modulemap的文件。
image.png
  1. 配置工程BuildSettingSwift Compiler - Search Paths選項(xiàng),值為module.modulemap文件所在的目錄路徑或其上層目錄路徑。
image.png

此處可為:

${SRCROOT}/MixFrameworkTest
${SRCROOT}/MixFrameworkTest/ObjcInSwitApp

如果這里的路徑配置不正確便會(huì)報(bào)錯(cuò):error build: No such module '*'

4.配置module.modulemap內(nèi)容

module OcInApp {
    // 所引入頭文件相對(duì)于`.modulemap`的路徑; "./OcClassInApp.h"也可以
    header "OcClassInApp.h" 
    export *
}
  1. import導(dǎo)入使用
import OcInApp
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        OcClassInApp.description()
    }
}

混入OC Framework

如果引入的OC FrameWork中含有Modules/module.modulemap文件,則直接拖入Swift工程中,使用import引入并進(jìn)行調(diào)用即可。

如果OC FrameWork不支持modulemap(沒有module.modulemap文件),則有兩種方法:

方法一

建立橋接文件,按需導(dǎo)入頭文件

方法二

基于OC FrameWork/Modules/module.modulemap路徑,創(chuàng)建module.modulemap文件,并輸入以下內(nèi)容并保存,之后便可使用import引入并進(jìn)行調(diào)用。

// 按需導(dǎo)入
framework module SameAsFrameWorkName { //必須與導(dǎo)入的`OC Framework`同名
  header "A.h"
  header "B.h"
  header "b.h"
  //..
  export *
}
///遞歸導(dǎo)入
framework module SameAsFrameWorkName { //必須與導(dǎo)入的`OC Framework`同名
  umbrella header "SameAsFrameWorkName.h" //SDK對(duì)外頭文件,包含SDK對(duì)外暴露的諸多.h文件

  export *
  module * { export * }
}

混入OC xcframework

與混入OC framework操作基本一致,如果引入的OC xcframework下不同的架構(gòu)文件下的framework中含有Modules/module.modulemap文件,則直接拖入Swift工程中,使用import引入并進(jìn)行調(diào)用即可。

如果OC xcframework不支持modulemap,也是有兩種方法:

方法一

建立橋接文件,按需導(dǎo)入頭文件。

方法二

對(duì)OC xcframework下不同架構(gòu)framework,參考混入OC framework的方法二,即可調(diào)用。

Swift Framework

當(dāng)Swift Framework僅有Swift類時(shí),如果是需要SDK外部使用的ClassMethod,則只需要使用publicopen修飾。

image.png

Swift工程導(dǎo)入Swift Framework后,直接在Swift的工程中使用即可。

import RadarSDK
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        RadarEntry.start()
    }
}

注意:Swift Framework中是不支持使用橋接文件的,不然的話會(huì)報(bào)錯(cuò):

image.png

混入OC/C/C++代碼

示例工程結(jié)構(gòu)如下:

image.png

內(nèi)部使用 OC

SDK內(nèi)部的Swift類,不能直接使用OC的代碼,并且不支持橋接文件。因此只能使用module.modulemap文件

  1. 創(chuàng)建文件名必須為module 后綴為.modulemap的文件。
  2. 配置工程BuildSettingSwift Compiler - Search Paths選項(xiàng),值為module.modulemap文件所在的目錄路徑或其上層目錄路徑,此處可為:
${SRCROOT}/SwiftMixSDK/ObjcSources
${SRCROOT}/SwiftMixSDK
  1. 配置module.modulemap內(nèi)容
module ObjcInFramwork {
    header "ObjcClassA.h"
    header "ObjcClassB.h"
    export *
}
  1. 使用
import ObjcInFramwork
public class SwiftMixTest: NSObject {
   public static func mixTest() {
        ObjcClassA.description()
        print("Swift MixIn OC")
    }
}

外部使用OC

如果Swift Framework外部需要調(diào)用混入的OC,有兩種方法:

方法一

Swift Framework外接.h頭文件以#import <SwiftMixSDK/PublicHeader.h>的方法對(duì)外公開需要使用的OC頭文件。

  1. 配置 Frame Targetbuild Phases,使得OC頭文件公開
image.png


image.png
  1. Swift Framework外接.h文件import需要公開的OC頭文件
    image.png
  1. 使用
import UIKit
import SwiftMixSDK
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        SwiftMixTest.mixTest()
        ObjcClassA.description()
        ObjcClassB.description()
    }
}
  1. 編譯最終產(chǎn)物對(duì)外暴露的頭文件
image.png


image.png

方法二

自定義Swift Framework.modulemap文件。

  1. 自定義module.modulemap文件;此處的文件名不強(qiáng)制module,但建議用module,因?yàn)榫幾g器最終會(huì)合并自定義的文件,最終導(dǎo)出module.modulemap文件。
  2. 配置 Frame Targetbuild Setting,保證Define ModuleYES; Module Map File 為自定義.modulemap文件的路徑。
image.png
  1. 配置module.modulemap內(nèi)容
framework module SwiftMixSDK {
    umbrella header "SwiftMixSDK.h"
    export *
    module * {export *}
    module ObjcInFramwork {
        header "/Users/*/Desktop/*/SwiftSDKExample/SwiftMixSDK/ObjcSources/ObjcClassA.h"
        header "/Users/*/Desktop/*/SwiftSDKExample/SwiftMixSDK/ObjcSources/ObjcClassB.h"
        export *
    }
}

最終SDKmodulemap:

image.png

值得注意的是,此處的header,只能使用絕對(duì)路徑,否則會(huì)出錯(cuò)。 stackoverflow此問題的QA

  1. 使用
import UIKit
import SwiftMixSDK.ObjcInFramwork
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        SwiftMixTest.mixTest()
        ObjcClassA.description()
        ObjcClassB.description()
    }
}
  1. 編譯最終產(chǎn)物對(duì)外暴露的頭文件
image.png

小結(jié)

綜上可以看出,兩種方法編譯的最終產(chǎn)物存在差異:

方法一會(huì)暴露OC頭文件的;方法二會(huì)隱藏OC的頭文件。
多人協(xié)作開發(fā)Swift Framework時(shí),方法二會(huì)存在頻繁修改.modulemap文件文件。因此實(shí)際開發(fā)中還得基于項(xiàng)目決定方案。

混入OC Framework

當(dāng)OC Framework不支持Module時(shí),有兩種方式混入OC Framework

方法一

通過使用.modulemap文件,實(shí)現(xiàn)對(duì)OC Framework調(diào)用。即:OC Framework支持(自動(dòng)或者手動(dòng))module

方法二

參考上述 混入OC/C/C++代碼 —— 內(nèi)部使用OC ,創(chuàng)建module.modulemap文件,配置相關(guān)Building Setting。配置module.modulemap內(nèi)容如下:

module ObjcFramwork {
    ///相對(duì)于module.modulemap的相對(duì)路徑
    umbrella header "../ObjcFramwork.framework/Headers/ObjcFramwork.h"
    export *
    module * { export * }
}

最后在Swift文件中import ObjcFramwork,即可調(diào)用。

混入OC xcframework

當(dāng)OC xcframework不支持Module時(shí),有兩種方式混入OC xcframework

方法一
對(duì)OC xcframework下不同架構(gòu)framework,參考混入OC Framework方法一,進(jìn)行操作后即可調(diào)用。

方法二

參考上述 混入OC/C/C++代碼 —— 內(nèi)部使用OC ,創(chuàng)建module.modulemap文件,配置相關(guān)Building Setting

這些操作與混入OC Framework方法二一致,唯一有區(qū)別在于:OC xcframework包含多種架構(gòu)的Framework

image.png

因此不能通過相對(duì)路徑直接引入,因?yàn)椴煌軜?gòu)路徑下的同一個(gè)頭文件會(huì)相互覆蓋而報(bào)錯(cuò);

image.png

如何解決呢?我們可以通過新建一個(gè)ObjcXCFramwork-umbrella.h文件(可以是其它名稱),并在其中引入xcframework的頭文件:

#import <MyTestSDK/MyTestSDK.h>

然后配置module.modulemap內(nèi)容如下:

module ObjcXCFramwork {
  umbrella header "ObjcXCFramwork-umbrella.h"

  export *
  module * { export * }
}

最后在Swift文件中import ObjcXCFramwork,即可調(diào)用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容