如何从 Swift 调用 Objective-C 代码?

How do I call Objective-C code from Swift?

提问人:David Mulder 提问时间:6/3/2014 最后编辑:TylerHDavid Mulder 更新时间:8/15/2023 访问量:370181

问:

在 Swift 中,如何调用 Objective-C 代码?

苹果提到它们可以在一个应用程序中共存,但这是否意味着人们可以在技术上重用用 Objective-C 中的旧类,同时在 Swift 中构建新类?

目标-C Swift

评论

14赞 rickster 6/3/2014
请参阅 Apple 的 Swift 与 Cocoa 和 Objective-C 配合使用指南。
2赞 John Riselvato 6/4/2014
developer.apple.com/library/prerelease/ios/documentation/Swift/......
1赞 David Mulder 6/7/2014
@AnalogFile:1)重复文档资源是StackOverflow完全可以处理的事情。显然,我不是唯一一个想知道的人,因为大多数人都是从谷歌来到这里的。2)阅读赏金说明;-)
6赞 Analog File 6/7/2014
@EvolGate:Objective C 究竟缺少什么,阻止它成为独立于平台的语言?语言和语言标准库是开源的。您可以在 Windows、Os X、Linux、BSD、Solaris 以及 GCC 或 LLVM 支持的任何其他平台中使用 Objective C。您可以轻松地将 Objective C 移植到任何具有良好 C 编译器的平台上,即使 GCC 和 LLVM 都不支持它。我看不出它如何比这更独立于平台。
3赞 franck 4/21/2016
@DavidMulder:“推理”部分还需要吗?

答:

133赞 rickster 6/3/2014 #1

请参阅 Apple 的 Swift 与 Cocoa 和 Objective-C 配合使用指南。本指南介绍了如何使用 Swift 中的 Objective-C 和 C 代码,反之亦然,并就如何在现有项目中转换项目或混合和匹配 Objective-C/C 和 Swift 部分提供了建议。

编译器自动生成用于调用 C 函数和 Objective-C 方法的 Swift 语法。从文档中可以看出,这个 Objective-C:

UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];

变成这个 Swift 代码:

let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)

Xcode 还可以即时进行这种转换——你可以在编辑 Swift 文件时使用 Open Quickly 并键入 Objective-C 类名,它会将你带到类头的 Swift 化版本。(您也可以通过 cmd 单击 Swift 文件中的 API 符号来获取此信息。iOS 8OS X v10.10 (Yosemite) 开发人员库中的所有 API 参考文档都以 Objective-C 和 Swift 形式(例如 UIView)可见。

评论

3赞 skywinder 6/4/2014
Apple 文档的直接链接如何将 Swift 集成到现有项目中:developer.apple.com/library/prerelease/ios/documentation/Swift/...
0赞 mfaani 8/11/2019
如果您对为什么需要头文件以及如何在链接阶段使用它感兴趣,那么请务必阅读这本 Swift 手册:了解 Swift/Objective-C 构建流水线
0赞 gnasher729 12/14/2021
更简单:let myTableView = UITableView(...)
28赞 Gergo Erdosi 6/3/2014 #2

引用文档

任何可作为模块访问的 Objective-C 框架(或 C 库) 可以直接导入 Swift。这包括所有 Objective-C 系统框架,例如 Foundation、UIKit 和 SpriteKit - 以及系统提供的通用 C 库。为 例如,要导入 Foundation,只需将此 import 语句添加到 您正在处理的 Swift 文件的顶部:

import Foundation

此导入使所有 Foundation API(包括 NSDate、NSURL、 NSMutableData 及其所有方法、属性和 类别 - 直接在 Swift 中可用。

1556赞 Logan 6/3/2014 #3

在 Swift 中使用 Objective-C 类

如果您有要使用的现有类,请执行步骤 2,然后跳到步骤 5。(在某些情况下,我不得不在较旧的 Objective-C 文件中添加显式。#import <Foundation/Foundation.h

Step 1: Add Objective-C Implementation -- .分钟

将文件添加到您的类中,并将其命名为 ..mCustomObject.m

第 2 步:添加桥接标头

添加文件时,您可能会遇到如下所示的提示:.m

A macOS sheet-style dialog from Xcode asking if you would "like to configure an Objective-C bridging header"

单击“是

如果您没有看到提示,或者不小心删除了桥接标头,请将新文件添加到您的项目中并将其命名为 。.h<#YourProjectName#>-Bridging-Header.h

在某些情况下,尤其是在使用 Objective-C 框架时,您不会显式添加 Objective-C 类,并且 Xcode 找不到链接器。在这种情况下,请创建如上所述命名的文件,然后确保在目标的项目设置中链接其路径,如下所示:.h

An animation demonstrating the above paragraph

注意:

最佳做法是使用宏链接项目,这样,如果您移动项目,或者使用远程存储库与其他人一起处理项目,它仍然可以工作。 可以将其视为包含 .xcodeProj 文件的目录。它可能看起来像这样:$(SRCROOT)$(SRCROOT)

$(SRCROOT)/Folder/Folder/<#YourProjectName#>-Bridging-Header.h

第 3 步:添加 Objective-C 头文件 -- .h

添加另一个文件并将其命名为 。.hCustomObject.h

第 4 步:构建 Objective-C 类

CustomObject.h

#import <Foundation/Foundation.h>

@interface CustomObject : NSObject

@property (strong, nonatomic) id someProperty;

- (void) someMethod;

@end

CustomObject.m

#import "CustomObject.h"

@implementation CustomObject 

- (void) someMethod {
    NSLog(@"SomeMethod Ran");
}

@end

第 5 步:向 Bridging-header 添加类

在:YourProject-Bridging-Header.h

#import "CustomObject.h"

第 6 步:使用对象

在:SomeSwiftFile.swift

var instanceOfCustomObject = CustomObject()
instanceOfCustomObject.someProperty = "Hello World"
print(instanceOfCustomObject.someProperty)
instanceOfCustomObject.someMethod()

无需显式导入;这就是桥接头的用途。

在 Objective-C 中使用 Swift 类

第 1 步:创建新的 Swift 类

将文件添加到项目中,并将其命名为 。.swiftMySwiftObject.swift

在:MySwiftObject.swift

import Foundation

@objc(MySwiftObject)
class MySwiftObject : NSObject {

    @objc
    var someProperty: AnyObject = "Some Initializer Val" as NSString

    init() {}

    @objc
    func someFunction(someArg: Any) -> NSString {
        return "You sent me \(someArg)"
    }
}

第 2 步:将 Swift 文件导入 ObjC 类

在:SomeRandomClass.m

#import "<#YourProjectName#>-Swift.h"

该文件:应该已经在您的项目中自动创建,即使您看不到它。<#YourProjectName#>-Swift.h

第 3 步:使用课程

MySwiftObject * myOb = [MySwiftObject new];
NSLog(@"MyOb.someProperty: %@", myOb.someProperty);
myOb.someProperty = @"Hello World";
NSLog(@"MyOb.someProperty: %@", myOb.someProperty);

NSString * retString = [myOb someFunctionWithSomeArg:@"Arg"];

NSLog(@"RetString: %@", retString);

笔记:

  1. 如果代码完成功能未按预期运行,请尝试运行快速构建,以帮助 Xcode 从 Swift 上下文中找到一些 Objective-C 代码,反之亦然。R

  2. 如果您将文件添加到较旧的项目并收到错误,请尝试完全重新启动 Xcode.swiftdyld: Library not loaded: @rpath/libswift_stdlib_core.dylib

  3. 虽然最初可以使用纯 Swift 类(不是 的后代),这些类通过使用前缀对 Objective-C 可见,但这不再可能。现在,要在 Objective-C 中可见,Swift 对象必须是符合的类(最简单的方法是继承自 ),或者是用某种整数类型的原始值标记的,例如 。您可以查看使用 @objc 的 Swift 1.x 代码示例的编辑历史记录,而不受这些限制。NSObject@objcNSObjectProtocolNSObjectenum@objcInt

评论

6赞 Tomáš Linhart 6/3/2014
重要的是,您需要使用 @objc 注释方法,否则 Swift 方法在 Objective-C 中将不可见。
31赞 Tomáš Linhart 6/3/2014
你是对的。只有在不使用 Cocoa 对象时才需要指定它。为了在 Objective-C 中可访问和可用,Swift 类必须是 Objective-C 类的后代,或者必须标记为 @objc。
2赞 Logan 6/4/2014
@MarkusRautopuro - 从这里得到它:developer.apple.com/library/prerelease/ios/documentation/Swift/......"
2赞 Stuart M 6/5/2014
Смотритетакже: WWDC 2014 会议 406:将 Swift 与 Objective-C 集成
6赞 jeremywhuff 11/21/2014
如果将 Objective C 框架导入 Swift,请确保将 Obj C 框架所依赖的所有框架导入到您的项目中(在 Build Phases -> Link Binary With Libraries 中),然后将这些框架的 #import 添加到前缀头文件中,该文件必须在构建设置中添加到您的项目中(在 Prefix Header 字段中)。这包括像 UIKit 和 Foundation 这样的框架,即使它们已经在 Swift 中使用了。这让我绊倒了几个小时,似乎没有人记录这些步骤。
45赞 Jake Lin 6/4/2014 #4

你可以阅读 Swift & Cocoapods 的好文章。基本上,我们需要创建一个桥接头文件,并将所有 Objective-C 头文件放在那里。然后我们需要从我们的构建设置中引用它。之后,我们可以使用 Objective-C 代码。

let manager = AFHTTPRequestOperationManager()
manager.GET(
  "http://example.com/resources.json",
  parameters: nil,
  success: { (operation: AFHTTPRequestOperation!,
              responseObject: AnyObject!) in
      println("JSON: " + responseObject.description)
  },
  failure: { (operation: AFHTTPRequestOperation!,
              error: NSError!) in
      println("Error: " + error.localizedDescription)
  })

也可以看看 Apple 的文档 Using Swift with Cocoa and Objective-C

30赞 Gian Luigi Romita 6/13/2014 #5

我写了一个简单的Xcode 6项目,展示了如何混合C++,Objective-C和Swift代码:

https://github.com/romitagl/shared/tree/master/C-ObjC-Swift/Performance_Console

特别是,该示例从 Swift 调用 Objective-C 和 C++ 函数

关键是创建一个共享标头 Project-Bridging-Header.h,并将 Objective-C 标头放在其中。

请下载该项目作为完整示例。

70赞 derrrick 2/13/2015 #6

以下是在 Swift 项目中使用 Objective-C 代码(在本例中为第三方提供的框架)的分步说明:

  1. 通过选择“文件”-“新建”-“新建文件”->“Objective-C 文件”,将任何 Objective-C 文件添加到 Swift 项目中>>新建文件。保存后,Xcode 会询问您是否要添加桥接标头。选择“”。Gif: adding empty file to project and generating bridging header
    (来源:derrrick.com

只需简单的步骤:

  1. 出现提示,然后单击“确定...”如果它没有出现,那么我们手动创建它,如下所示......从 iOS 源代码创建一个头文件,并命名为 ProjectName-Bridging-Header(例如:Test-Bridging-Header),然后转到 Swift 编译器代码中的构建设置> Objective-C 桥接添加 Objective-C 桥接名称。(测试/Test-Bridging-Header.h)。是的,这就完成了。

  2. 或者,删除您添加的 Objective-C 文件(在上面的 GIF 图像中名为“anything”)。你不再需要它了。

  3. 打开桥接头文件 -- 文件名的格式为 [YourProject]-Bridging-Header.h。它包括 Xcode 提供的注释。为要包含的 Objective-C 文件(如第三方框架)添加一行代码。例如,若要将 Mixpanel 添加到项目中,需要将以下代码行添加到桥接头文件中:

    #import "Mixpanel.h"
  4. 现在,在任何 Swift 文件中,您都可以使用 Swift 语法(在本例中,您可以调用 Mixpanel SDK 方法等)使用现有的 Objective-C 代码。您需要熟悉 Xcode 如何将 Objective-C 转换为 Swift。Apple 的指南是快速阅读的。或者查看此答案以获取不完整的摘要。

Mixpanel 示例:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    Mixpanel.sharedInstanceWithToken("your-token")
    return true
}

就是这样!

注意:如果从项目中删除桥接头文件,请务必进入 Build Settings 并删除 “Swift Compiler - Code Generation” 下的 “Objective-C Bridging Header” 值。

9赞 Yogesh shelke 9/10/2015 #7

单击“新建文件”菜单,然后选择“文件选择语言目标”。此时,它会自动生成一个“Objective-C Bridging Header”文件,用于定义某个类名。

“Swift Compiler - Code Generation”下的“Objective-C Bridging Header”。

30赞 Mehul Patel 9/16/2015 #8

我还想在这里补充一点:

我非常感谢@Logan的回答。它对创建桥接文件和设置有很大帮助。

但是在完成所有这些步骤之后,我仍然没有在 Swift 中获得 Objective-C 类。

我使用了该库并将其集成到我的项目中。这是.cocoapodspod "pop"

因此,如果你在 Swift 中使用 Objective-C pod,那么你可能无法将类导入 Swift。import

你要做的简单的事情是:

  1. 转到文件并<YOUR-PROJECT>-Bridging-Header
  2. 将语句替换为#import <ObjC_Framework>@import ObjC_Framework

例如:(Pop library)

取代

#import <pop/POP.h>

@import pop;

#import 不工作时,请使用 clang import

评论

0赞 mfaani 12/2/2016
当 #import 不起作用时,请使用 clang import。什么?不是说我们应该用@import吗?!
14赞 Avijit Nagare 11/25/2015 #9

创建桥接头文件后,转到 Build Setting => 搜索 “Objective-C Bridging Header”。

在正下方,您将找到“Objective-C 生成的接口头名称”文件。

在视图控制器中导入该文件。

示例:在我的例子中:“Dauble-Swift.h”

eEter image description here

16赞 david72 3/21/2016 #10

对于试图向 Swift 添加 Objective-C 库的人,请注意:您应该在 Build Settings -> Linking -> Other Linker Flags 中添加 -ObjC

评论

0赞 Johan Karlsson 12/21/2018
为什么?请添加有关此标志的作用以及应添加它的原因的信息。
6赞 Nish 6/29/2017 #11
  1. 从 NewFile -> Source -> 头文件创建 .h 文件
  2. 然后保存文件的名称 Your_Target_Name-Bridging-Header.h 这里的人通过获取他们的项目名称而犯了常见的错误,但如果两者不同,它应该是项目的目标名称,通常它们是相同的。
  3. 然后在构建设置中搜索 Objective-C 桥接标头标志并输入新创建的桥接文件的地址,您可以右键单击文件 - >显示在查找器中 - >将文件拖动到文本区域,然后地址将被填充。
  4. 使用 #import Your_Objective-C_file.h
  5. 在 swift 文件中,您可以访问 ObjC 文件,但只能使用 swift 语言。
3赞 Sanjay Mali 4/13/2018 #12

在 Swift 中使用 objective-c 编码的两种方法

1

1. Create bridge-header.h file in Xcode Project
2. import .h file in bridge-Header file
3. Set path of bridge-Header in Build settings. 
3. Clean the Project 

2

  1. Create objective-c files in project(it automatically set path in Build Settings for you )
  2. import .h file in bridge-Header file
7赞 Andy Jazz 6/13/2018 #13

在 Xcode 10.1 的 Swift 4.2.1 项目中,您可以轻松添加 Objective-C 文件。按照以下步骤将 Objective-C 文件桥接到 Swift 项目。

Step_01:使用 Swift 语言创建新的 Xcode 项目:

File > New > Project > objc.

Step_02:在 Swift 项目中添加新的 Objective-C 文件:

File > New > File... > macOS > Objective-C File.

Step_03:如果你在第一次向 Swift 项目中添加一个新的 Objective-C 文件,Xcode 会询问你:

Would you like to configure an Objective-C bridging header?

enter image description here

Step_04:选择以下选项:

Create Bridging Header.

Step_05:将生成一个名称为:

Objc-Bridging-Header.h.

enter image description here

Step_06:现在,您需要在桥接头中设置桥接文件路径。在“项目导航器”中,单击“带名称的项目”,然后选择:objc

Build Settings > Objective-C Bridging Header > Objc-Bridging-Header.h.

Step_07:将 your 拖放到该框中以生成文件路径。Objc-Bridging-Header.h

enter image description here

Step_08:打开文件并导入要在 Swift 文件中使用的 Objective-C 文件。Objc-Bridging-Header.h

#import "SpecialObjcFile.m"

以下是以下内容:SpecialObjcFile.m

#import <Foundation/Foundation.h>

@interface Person: NSObject {
@public
    bool busy;
}
@property
    bool busy;
@end

Step_09:现在在你的 Swift 文件中,你可以使用 Objective-C 类:

override func viewDidLoad() {
    super.viewDidLoad()
    let myObjcContent = Person()
    print(myObjcContent.busy)
}

enter image description here enter image description here

2赞 Tibin Thomas 1/5/2019 #14

Apple 在此文档中提供了官方指南:how-to-call-objective-c-code-from-swift

以下是相关部分:

若要将一组 Objective-C 文件导入到同一应用目标中的 Swift 代码中,需要依靠 Objective-C 桥接头文件将这些文件公开给 Swift。当您将 Swift 文件添加到现有 Objective-C 应用或将 Objective-C 文件添加到现有 Swift 应用时,Xcode 会创建此标头。

如果您接受,Xcode 将创建桥接头文件以及您正在创建的文件,并使用您的产品模块名称后跟“-Bridging-Header.h”对其进行命名。或者,您也可以通过选择“文件”>“新建>文件”>“[操作系统]”>“源>头文件”来自行创建桥接头

编辑桥接标头,将 Objective-C 代码公开给 Swift 代码:

  1. 在 Objective-C 桥接头文件中,导入要公开给 Swift 的每个 Objective-C 头文件
  2. 在“生成设置”的“Swift 编译器 - 代码生成”中,确保“Objective-C 桥接头文件”生成设置具有桥接头文件的路径。该路径应相对于项目,类似于在“生成设置”中指定 Info.plist 路径的方式。在大多数情况下,您不需要修改此设置。

桥接标头中列出的任何公共 Objective-C 标头对 Swift 都是可见的。

3赞 Sazzad Hissain Khan 5/21/2019 #15

Logans 的答案工作正常,除了在最新时它给出了一些编译器错误。这是针对正在使用 Swift 5 的人的修复程序。Swift 5

斯威夫特 5

import Foundation

class MySwiftObject : NSObject {

    var someProperty: AnyObject = "Some Initializer Val" as AnyObject

    override init() {}

    func someFunction(someArg:AnyObject) -> String {
        let returnVal = "You sent me \(someArg)"
        return returnVal
    }
}
17赞 yoAlex5 12/7/2019 #16

混合使用 Objective-C 和 Swift

高电平图:

同一目标

//Objective-C exposes API for Swift through <target_name>-Bridging-Header.h
.swift uses .h.m = Swift consumer, Objective-C producer = <target_name>-Bridging-Header.h

//Swift exposes API for Objective-C through <target_name>-Swift.h
.h.m uses .swift = Objective-C consumer, Swift producer = <target_name>-Swift.h

Swift 消费者,Objective-C 生产者

  1. 添加新的头文件和实现文件 - Cocoa 类文件(Objective-C)
    例如和
    .h.m<MyFileName>.h<MyFileName>.m

  2. 配置桥接标头
    当您看到单击 -
    Would you like to configure an Objective-C bridging header

    • <target_name>-Bridging-Header.h将自动生成
    • 构建设置 -> Objective-C 桥接头文件(SWIFT_OBJC_BRIDGING_HEADER)
  3. 将类添加到桥接头
    在添加一行
    <target_name>-Bridging-Header.h#import "<MyFileName>.h"

之后,您可以使用 from ,SwiftObjective-C'sMyFileName.hMyFileName.m

P.S. 如果你应该将现有的 Objective-C 文件添加到 Swift 项目中,请事先添加并导入它Bridging-Header.h

Objective-C 消费者,Swift 生产者

  1. 添加 a 和 extends<MyFileName>.swiftNSObject

  2. 将 Swift 文件导入 ObjC 类
    添加到您的 Objective-C 文件中
    #import "<target_name>-Swift.h"

  3. 通过 [关于] 公开公共 Swift 代码@objc

之后,您可以使用Objective-C Swift's <MyFileName>.swift

[未找到 <product_name>-Swift.h 文件]

不同的目标 [.modulemap] 和 [umbrella.h] 用于公开 Swift 的 Objective-C。以及用于公开 Objective-C 的 Swift 代码Swift.h

[词汇]

3赞 roadRunner 9/29/2020 #17

使任何 Swift 类成为 NSObject 的子类也是有意义的,我更喜欢使用任何 Swift 类在 Objective-C 类中看到,例如:

@objc(MySwiftClass)
@objcMembers class MySwiftClass {...}