裝模作樣寫(xiě)個(gè)前言
背景:擁有悠久歷史的大型SDK篡腌,這個(gè)歷史當(dāng)然是Objective-C术吝。又當(dāng)然這個(gè)是沒(méi)有問(wèn)題的,而且每天都在服務(wù)上千萬(wàn)用戶罩引,但是不巧的是Apple出了一個(gè)StoreKit2,按理說(shuō)每年蘋(píng)果爸爸都要出很多API枝笨,這很正常袁铐。但是又不巧的是它只支持 Swift 編寫(xiě),而且這樣的API我估計(jì)只會(huì)成為常態(tài)横浑,所以 Swift 化已經(jīng)刻不容緩了剔桨。
結(jié)果:半夜執(zhí)筆
溫馨提示:本文實(shí)例代碼已上傳github,附錄于(下)中徙融。
編譯環(huán)境:Xcode13.0 Swift5.5 arm64
如有不正洒缀,請(qǐng)?jiān)谠u(píng)論區(qū)告知我。
一、 在SDK內(nèi)部OC調(diào)用Swift
|新建兩個(gè) Swift 文件
import UIKit
@objc(TESTSWIFT)
@objcMembers
public
class TestSwift: NSObject {
public static func run() -> Void {
print("(#fileID): (#function)")
TestSwift2.run()
}
}
//TestSwift2.swift
class TestSwift2: NSObject {
static func run() -> Void {
print("(#fileID): (#function)")
}
}
解釋一下:
@objc 在這里主要是為了修改類(lèi)的名稱(chēng)树绩。
@objcMembers:在類(lèi)名前面是使用objcMembers修飾萨脑,系統(tǒng)會(huì)在自動(dòng)給這個(gè)類(lèi)的所有方法添加@objc,暴露給OC饺饭。
public 是為了暴露給外部OC調(diào)用者渤早。
|在OC中調(diào)用該Swift類(lèi)
#import "TestOC.h"
#import "TestOC2.h"
#import <SWSDK/SWSDK-Swift.h>
@implementation TestOC
+ (void) run {
NSLog(@"TestOC:SDK外放OC類(lèi)");
[TESTSWIFT run];
[TestOC2 run];
}
@end
這里主要操作是 #import <SWSDK/SWSDK-Swift.h>, 所有OC調(diào)用 Swift 的地方必須導(dǎo)入該頭文件瘫俊,為了方便導(dǎo)入鹊杖,我們可以在 PCH 文件中加入該頭文件。
我們可以看到Swift內(nèi)部類(lèi)不需要添加 @objc扛芽、@objcMembers骂蓖、public 等關(guān)鍵詞。
|我們來(lái)比對(duì)一下加入Swift前后的文件結(jié)構(gòu)變化
. //無(wú)Swift
├── Headers
│ ├── SWSDK.h
│ └── TestOC.h
├── Info.plist
├── Modules
│ └── module.modulemap
├── SWSDK
└── _CodeSignature
├── ...
. //增加Swift
├── Headers
│ ├── SWSDK-Swift.h
│ ├── SWSDK.h
│ └── TestOC.h
├── Info.plist
├── Modules
│ ├── SWSDK.swiftmodule
│ │ ├── ...
│ └── module.modulemap
├── SWSDK
└── _CodeSignature
├──...
//SWSDK-Swift.h文件
SWIFT_CLASS_NAMED("TestSwift")
@interface TESTSWIFT : NSObject
+ (void)run;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end
增加了 SWSDK-Swift.h 和 SWSDK.swiftmodule 目錄川尖。 PS: Swiftmodule文件夾需要模擬器與真機(jī)合并才可以對(duì)外使用涯竟。
SWSDK-Swift.h 主要是為了方便內(nèi)部OC調(diào)用。這里 Headers 的增加: 沒(méi)有進(jìn)行Build Phases 的 public 拖拽空厌,屬于自動(dòng)外放庐船。
SWSDK.swiftmodule:公共接口的定義文件。
Question:有人可能有疑問(wèn)嘲更,為什么SWSDK-Swift.h變成外放了筐钟?
|我們一起來(lái)看看modulemap文件的前后變化
framework module SWSDK {
umbrella header "SWSDK.h"
export *
module * { export * }
}
//加入Swift后新增的SWSDK.Swift
module SWSDK.Swift {
header "SWSDK-Swift.h"
requires objc
}
|所以?xún)?nèi)部可以調(diào)用SWSDK-Swift.h,由 modulemap 外放到 Headers 中赋朦,所以按邏輯來(lái)說(shuō)篓冲,在外部工程中也可以顯式的調(diào)用 SWSDK-Swift.h。
在AppDelegate.h中調(diào)用
#import "AppDelegate.h"
//#import <SWSDK/SWSDK.h>
#import <SWSDK/SWSDK-Swift.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// [TestOC run];
[TESTSWIFT run];
return YES;
}
//輸出
SWSDK/TestSwift.swift: run()
SWSDK/TestSwift2.swift: run()
|所以外部類(lèi)也可以正常調(diào)用Swift宠哄,只需要加上 #import<SWSDK/SWSDK-Swift.h> 頭文件壹将。
下一篇我們將介紹SDK內(nèi)部Swift調(diào)用OC的Module化方法