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


974

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

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


13
请参阅Apple关于将Swift与Cocoa和Objective-C结合使用的指南。
rickster 2014年


10
有趣的是,这个问题获得了很多好评和赏金。当我第一次看到它时,我只是想:RTFM。如前所述,它实际上没有任何研究,因为目前只有两到三个资源正式记录了Swift,其中一个完全致力于此目的(并在第一条评论中链接了)。
Analog File

6
@EvolGate:Objective C到底缺少什么阻止它成为平台无关的语言?语言和语言标准库是开源的。您可以在Windows,Os X,Linux,BSD,Solaris和GCC或LLVM支持的任何其他平台中以及其中使用ObjectiveC。即使GCC和LLVM都不支持,您也可以使用像样的C编译器轻松地将Objective C移植到任何平台。我看不出有什么比这更独立于平台的。
Analog File

2
@DavidMulder:是否仍需要“推理”部分?
franck

Answers:


1392

在Swift中使用Objective-C类

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

步骤1:添加Objective-C实施-.m

.m文件添加到您的班级,并命名为CustomObject.m

步骤2:添加桥接标题

添加.m文件时,可能会出现类似以下提示的提示:

Xcode的macOS工作表样式对话框,询问您是否“想配置Objective-C桥接标头”

单击

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

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

演示以上段落的动画

注意:

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

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

步骤3:添加Objective-C标头-.h

添加另一个.h文件并命名CustomObject.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类别

.swift文件添加到您的项目,并将其命名MySwiftObject.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. 如果代码完成不符合您的期望,请尝试运行一个快速构建,R以帮助Xcode从Swift上下文中找到一些Objective-C代码,反之亦然。

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

  3. 尽管最初可以NSObject通过使用@objc前缀使用对Objective-C可见的纯Swift类(不是的后代),但这不再是可能的。现在,要在Objective-C中可见,Swift对象必须是符合的类NSObjectProtocol(最简单的方法是从继承NSObject),或用诸如的整数类型的原始值enum标记。没有这些限制的情况下,您可以查看Swift 1.x代码示例的编辑历史记录@objcInt@objc


5
重要的是,您需要使用@objc注释方法,否则Swift方法将无法从Objective-C中看到。
托马斯·林哈特

29
你是对的。如果不使用Cocoa对象,则只需指定它。为了在Objective-C中可访问和使用,Swift类必须是Objective-C类的后代,或者必须标记为@objc。
托马斯·林哈特


2
另请参阅:WWDC 2014大会406:将Swift与Objective-C集成
Stuart M

6
如果要将Objective C框架导入Swift,请确保将Obj C框架所依赖的所有框架都导入到您的项目中(在Build Phases-> Link Binary With Libraries中),然后将这些的#import添加到前缀头文件中,必须在构建设置中(在“前缀标题”字段中)添加到项目中。这包括UIKit和Foundation之类的框架,即使它们已在Swift中使用。这使我绊了几个小时,似乎没有人记录这些步骤。
user1021430

121

请参阅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文件时使用“快速打开”并键入Objective-C类名称,然后将您带到类头的Swift版本。(您也可以通过cmd单击Swift文件中的API符号来获取此信息。)iOS 8OS X v10.10(Yosemite)开发人员库中的所有API参考文档在Objective-C和Swift中都可见形式(例如UIView)。


3
直接链接到苹果公司的文档如何Swift在现有项目的整合:developer.apple.com/library/prerelease/ios/documentation/Swift/...
skywinder

如果我们对为什么需要头文件以及在链接阶段如何使用头文件感兴趣,请确保阅读此手册:了解Swift / Objective-C构建管道
Honey,

62

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

  1. 通过选择File-> New-> New File-> Objective-C File 将任何Objective-C文件添加到您的Swift项目。保存后,Xcode会询问您是否要添加桥接标头。选择“ ”。(来源:derrrick.comGif:将空文件添加到项目并生成桥接头

简单的步骤:

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

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

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

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

Mixpanel示例:

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

而已!

注意:如果从项目中删除桥接头文件,请确保进入“构建设置”,并删除“快速编译器-代码生成”下“ Objective-C桥接头 ” 的值。


39

您可以阅读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)
  })

也可以看看苹果的文档《将Swift与Cocoa和Objective-C结合使用》。



24

我想在这里添加一件事:

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

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

我使用了cocoapods库并将其集成到我的项目中。哪个是pod "pop"

因此,如果您在Swift中使用Objective-C Pod,则可能会导致无法获取import类或将其放入Swift。

您要做的简单的事情是:

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

例如:(流行音乐库)

更换

#import <pop/POP.h>

@import pop;

clang import#import无法使用时使用。


#import不起作用时,请使用clang import。什么?不只是说我们应该使用@import吗?
蜂蜜

22

文档引用:

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

import Foundation

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


12

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


为什么?请添加有关此标志的作用以及添加原因的信息。
约翰·卡尔森

9

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

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

将该文件导入您的视图控制器。

示例:以我为例:“ Dauble-Swift.h”

此处的电子图像说明


5

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

“快速编译器-代码生成”下的“目标C桥接标头”。


3
  1. 从NewFile-> Source->头文件创建一个.h文件
  2. 然后保存文件名 Your_Target_Name-Bridging-Header.h 这里的人会因为使用他们的项目名称而犯了一个常见错误,但是如果两者不同(通常是相同的),那么它应该是项目目标的名称。
  3. 然后在构建设置中搜索Objective-C桥接头标志并放置新创建的桥接文件的地址,您可以右键单击该文件->在finder中显示->将该文件拖到文本区域中,然后该地址将被填充。
  4. 使用#import Your_Objective-C_file.h
  5. 在swift文件中,您可以访问ObjC文件,但只能使用swift语言。


3

在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

在此处输入图片说明

步骤_04:选择选项:

Create Bridging Header

步骤_05:将生成一个名称对应的文件:

Objc-Bridging-Header.h

在此处输入图片说明

步骤_06:现在,您需要在网桥头中设置网桥文件路径。在项目浏览器中,单击名称为的项目objc然后选择:

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

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

在此处输入图片说明

Step_08:打开Objc-Bridging-Header.h文件,然后将要使用的Objective-C文件导入Swift文件中。

#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)
}

在此处输入图片说明 在此处输入图片说明


1

洛根答案很好用,除非最近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
    }
}

1

迅速的消费者,Objective-C制作人

  1. 添加标头.h和实现.m文件-可可类文件(Objective-C)
    例如MyFileName

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

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

PS如果您应该将现有的Objective-C文件添加到Swift项目中,请Bridging-Header.h事先添加

Objective-C消费者,Swift制作人

  1. 添加<MyFileName>.swift和扩展NSObject

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

  3. 标记公共Swift代码[@objc和@objcMembers]


0

Apple已在此文档中提供了官方指南: 如何从Swift调用目标C代码

这是相关的部分:

要将一组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路径的方式。在大多数情况下,您无需修改​​此设置。

Swift可以看到桥接头中列出的所有公共Objective-C头。


0

使用Objective-C的两种方法Objective-C

1个

  1. 在Xcode Project中创建bridge-header.h文件
  2. 在网桥头文件中导入.h文件
  3. 在构建设置中设置bridge-Header的路径。
  4. 清理项目

2

  1. 在项目中创建Objective-C文件(它会在Build Settings中自动为您设置路径)
  2. 在网桥头文件中导入.h文件

现在好去 谢谢

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.