如何使 Swift 包在 Objective-C 项目中可导入/可用?

Jia*_*ang 7 objective-c ios swift swift-package-manager

我有一个仅用 Swift 编写的包,现在我想让它适用于 Objective-C 项目。我知道通常要在同一目标中使用 Swift 类,您可以使用为模块创建的桥接标头,但是当我通过 SPM 导入我的包时,没有提示创建桥接标头。这可能吗?我必须先以某些方式准备我的 swift 包裹吗?

Jia*_*ang 8

网上关于此的文档数量令人惊讶,但我终于弄清楚了。这并不像在 package.Swift 文件中进行一些更改并单击一些按钮那么容易,但幸运的是它也不是太难。我仍在努力使我的 Swift 库能够在 Objc 中使用,并将用我在此过程中发现的任何发现更新此答案,但这是迄今为止我所拥有的:

  1. Swift 中的类只有继承自 NSObject 才能在 objc 中使用
public final class MyObjcLibrary: NSObject {}
Run Code Online (Sandbox Code Playgroud)
  1. 要将其导出到 objc,您需要附加@objc关键字,并且可以使用关键字后面的括号指定 objc 代码使用的类名 - 当您的 objc 类只是带有一堆导出函数的包装器时,这非常方便你对应的 Swift 类:
@objc(MyLibrary)
public final class MyObjcLibrary: NSObject{}
Run Code Online (Sandbox Code Playgroud)

这样,您的库的用户就可以编写[MyLibrary alloc]而不是[MyObjcLibrary alloc].

  1. @objc现在,您可以在新类中添加用户需要使用的所有函数(使用关键字)。假设你有一个名为 Swift 类MyLibrary:
@objc(MyLibrary)
public final class MyObjcLibrary: NSObject{
  private var myLibrary: MyLibrary

  @objc public init() {
    myLibrary = MyLibrary()
  }

  @objc public static func doSomething(withID: String) {
    myLibrary.doSomething(withID)
  }

  @objc public static func doSomethingElse(ID: String) {
    myLibrary.doSomethingElse(ID)
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)
  1. 要在 objc 代码中导入和调用类和函数,只需通过 SPM、Cocoapods 等以添加 Swift 包的方式添加包,然后在 objc 类中添加:
@import MyPackage

...

[[MyLibrary alloc] init];
[MyLibrary doSomethingWithID:@"my_id"];
[MyLibrary doSomethingElseWithID:@"my_id"];
...
Run Code Online (Sandbox Code Playgroud)

请注意 objc 中函数的命名方式 - 如果第一个参数不以前缀“with”开头,则会自动为 objc 函数签名添加它,例如doSomethingElseWithID。

我见过的问题:

  • 当您的 Swift 库有更新时,有时您需要重新启动 Xcode 并删除 DerivedData 文件夹,以便使用更新的代码重新生成桥接头文件。