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

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

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

349398 次浏览

请参阅苹果的使用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 quick,并输入Objective-C类名,它会带你到Swift化的类头。(你也可以通过cmd点击Swift文件中的API符号来获得。)iOS  8OS X v10.10(约塞米蒂)开发人员库中的所有API参考文档在Objective-C和Swift表单中都是可见的(例如# 0)。

引用文档的话:

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

# 0

这个导入使所有的基础api -包括NSDate, NSURL,NSMutableData,以及它们所有的方法,属性和category -在Swift中直接可用

在Swift中使用Objective-C类

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

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

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

步骤2:添加桥接头

当添加.m文件时,你可能会看到如下提示:

一个来自Xcode的macOS表式对话框,询问您是否“想要配置一个Objective-C桥接头文件”;

点击# 0 !

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

在某些情况下,特别是在使用Objective-C框架时,你没有显式地添加Objective-C类,Xcode就找不到链接器。在这种情况下,创建你的.h文件命名如上所述,然后确保你链接它的路径在你的目标项目设置如下:

演示上述段落的动画 .

注意:

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

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

步骤3:添加Objective-C Header——.h

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

步骤4:构建Objective-C类

在# 0

#import <Foundation/Foundation.h>
@interface CustomObject : NSObject
@property (strong, nonatomic) id someProperty;
- (void) someMethod;
@end

在# 0

#import "CustomObject.h"
@implementation CustomObject
- (void) someMethod {NSLog(@"SomeMethod Ran");}
@end

步骤5:添加类到桥接头

在# 0:

#import "CustomObject.h"

第六步:使用你的对象

在# 0:

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

不需要显式地导入;这就是桥接头的作用。

在Objective-C中使用Swift类

步骤1:创建新的Swift类

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

在# 0:

import Foundation
@objc(MySwiftObject)class MySwiftObject : NSObject {
@objcvar someProperty: AnyObject = "Some Initializer Val" as NSString
init() {}
@objcfunc someFunction(someArg: Any) -> NSString {return "You sent me \(someArg)"}}

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

在# 0:

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

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

第三步:利用你的课程

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. 虽然最初可以使用纯Swift类(不是NSObject的后代),通过使用@objc前缀对Objective-C可见,但这已经不可能了。现在,为了在Objective-C中可见,Swift对象必须是一个符合NSObjectProtocol的类(最简单的方法是从NSObject继承),或者是一个标记为@objcenum,带有一些整数类型的原始值,如Int你可以查看Swift 1的编辑历史。X代码使用@objc,没有这些限制

你可以看看0号帖子。基本上,我们需要创建一个桥接头文件,并将所有Objective-C头文件放在那里。然后我们需要从构建设置中引用它。之后,我们可以使用Objective-C代码。

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

也可以看看苹果的文件使用Swift with Cocoa和Objective-C

我写了一个简单的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头文件放在那里。

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

以下是在Swift项目中使用Objective-C代码(在这种情况下,由第三方提供的框架)的逐步说明:

  1. 添加任何Objective-C文件到你的Swift项目通过选择文件->新建->新建文件-> Objective-C文件。在保存时,Xcode会询问你是否想要添加一个桥接头。选择“2”。# 3 < br >(来源:# 0)< /子>

步骤简单:

  1. 出现提示,然后单击OK…如果它没有出现,那么我们手动创建它,如下所示…从iOS源代码创建一个头文件,并将其命名为ProjectName-Bridging-Header(例如:Test- bridging - header),然后在Swift编译器代码中构建设置-> Objective-C bridge添加Objective-C bridge name ..(Test/Test- bridging - header .h)。是的,这是完整的。

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

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

    #import "Mixpanel.h"
  4. Now in any Swift file you can use existing Objective-C code, in the Swift syntax (in the case of this example, and you can call Mixpanel SDK methods, etc.). You need to familiarize yourself with how Xcode translates Objective-C to Swift. Apple's guide is a quick read. Or see this answer for an incomplete summary.

Example for Mixpanel:

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

就是这样!

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

点击文件菜单,并选择文件选择语言目标。这时,它会自动生成一个“Objective-C Bridging Header”文件,用于定义一些类名。

“Swift编译器-代码生成”下的“Objective-C桥接头”。

我还想补充一点:

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

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

我使用cocoapods库并将其集成到我的项目中。这是第一条。

所以如果你在Swift中使用Objective-C pod,那么可能有一个机会,你不能获得或import类到Swift中。

你要做的一件简单的事情是:

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

例如:(Pop library)

取代

#import <pop/POP.h>

@import pop;

#import不起作用时使用clang import

创建桥接头后,进入构建设置=>搜索“Objective-C桥接头”。

就在下面你会发现“Objective-C Generated Interface Header Name”文件。

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

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

eEter image description here

给那些试图向Swift添加Objective-C库的人一个提示:你应该在建立设置 -> 链接 -> 其他链接标志中添加objc

  1. 从NewFile -> Source ->头文件创建一个。h文件
  2. 这里的人会犯一个常见的错误,他们会取他们的项目名,但如果两者不一样,应该是项目目标的名字,通常它们是相同的。
  3. 然后在构建设置中搜索Objective-C桥接头标志,并把你新创建的桥接文件的地址,你可以右键单击文件-> show in finder ->在文本区域拖动文件,然后地址将被填充。
  4. 使用#import Your_Objective-C_file.h
  5. 在swift文件中,您可以访问ObjC文件,但只能使用swift语言。

使用objective-c的双向方法

1

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

2

  1. 在项目中创建objective-c文件(它会自动在Build Settings中为您设置路径)
  2. 在bridge-Header文件中导入.h文件

现在可以开始了由于< / >强

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

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

File > New > Project > #

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

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

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

# 0 ?

enter image description here

Step_04:选择选项:

# 0。

Step_05:将生成一个对应的文件,文件的名称如下:

# 0。

enter image description here

Step_06:现在,你需要在桥标头中设置桥文件路径。在Project Navigator中单击名称为objc的项目,然后选择:

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

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

enter image description here

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

#import "SpecialObjcFile.m"

这里是SpecialObjcFile.m的内容:

#import <Foundation/Foundation.h>
@interface Person: NSObject {@publicbool busy;}@propertybool busy;@end

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

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

enter image description here# 0 < / p >

苹果在这个文档中提供了官方指南:# 0 < / p >

以下是相关部分:

为了将一组Objective-C文件导入到同一个应用目标中的Swift代码中,你依赖于 object - c桥接头文件将这些文件公开给Swift。当你将一个Swift文件添加到一个现有的Objective-C应用程序中,或者将一个Objective-C文件添加到一个现有的Swift应用程序中时,Xcode提供了创建这个头文件的功能。

如果你接受,Xcode会创建桥接头文件和你创建的文件一起,并使用你的产品模块名后跟"-Bridging-Header.h"来命名它。或者,你也可以自己创建一个桥接头,方法是选择文件>新建>文件>[操作系统]>源>头文件

编辑桥接头,将Objective-C代码暴露给Swift代码:

  1. # 0。
  2. 在构建设置中,在Swift Compiler - Code Generation中,确保Objective-C桥接头构建设置具有桥接头文件的路径。路径应该是相对于你的项目,类似于你的信息的方式。plist路径在Build Settings中指定。在大多数情况下,您不需要修改此设置。

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

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

混合Objective-C和Swift

高层图:

相同的目标

//Objective-C exposes API for Swift thought <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 thought <target_name>-Swift.h.h.m uses .swift = Objective-C consumer, Swift producer = <target_name>-Swift.h

Swift消费者,Objective-C生产者

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

  1. 配置桥接头
    当你看到Would you like to configure an Objective-C bridging header时,点击- 是的

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

之后你可以使用Swift Objective-C's MyFileName.h MyFileName.m

附注:如果你要在Swift项目中添加现有的 Objective-C文件,请预先添加Bridging-Header.h并导入它

Objective-C消费者,Swift生产者

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

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

  3. 通过@objc <一口>[对]< /一口>公开Swift代码

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

[<product_name>-Swift.h file not found

< >强不同的目标(.modulemap)(umbrella.h)用于为Swift公开Objective-C。Swift.h为Objective-C公开Swift代码

< a href = " https://stackoverflow.com/a/59216151/4770877 " > < / >(词汇)

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

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