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

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

评论

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

developer.apple.com/library/prerelease/ios/documentation/Swift / ...

有趣的是,这个问题得到了很多好评和赏金。当我第一次看到它时,我只是想:RTFM。就目前而言,它并没有显示任何研究成果,因为目前只有两三个资源正式记录了Swift,而其中一个资源完全致力于此(并在第一条评论中链接了)。

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

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

#1 楼

在Swift中使用Objective-C类


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


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

添加.m文件并命名为CustomObject.m

步骤2:添加桥接标头

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



单击“是”!

如果没有看到提示,或者不小心删除了桥接标题,请在项目中添加一个新的.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:在CustomObject.h中构建您的Objective-C类

 #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:在YourProject-Bridging-Header.h中将类添加到Bridging-Header中


br />第6步:使用对象

#import "CustomObject.h" 中:

 SomeSwiftFile.swift 


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

在Objective-C中使用Swift类

步骤1:创建新的Swift类

在您的项目中添加一个var instanceOfCustomObject = CustomObject() instanceOfCustomObject.someProperty = "Hello World" print(instanceOfCustomObject.someProperty) instanceOfCustomObject.someMethod() 文件,并将其命名为.swift

MySwiftObject.swift中:

 MySwiftObject.swift 


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

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)" } } 中:

 SomeRandomClass.m 


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

步骤3:使用您的课程

 <#YourProjectName#>-Swift.h 


注意:


如果代码完成不符合您的期望,请尝试使用以下命令运行快速构建⌘⇧R帮助Xcode从Swift上下文中找到一些Objective-C代码,反之亦然。
如果将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); 文件添加到较旧的项目中并出现错误.swift,请尝试完全重新启动Xcode。
虽然最初可以使用对物镜可见的纯Swift类(不是dyld: Library not loaded: @rpath/libswift_stdlib_core.dylib的后代) -C通过使用NSObject前缀,将不再可能。现在,要在Objective-C中可见,Swift对象必须是符合@objc的类(最简单的方法是从NSObjectProtocol继承),或者是标记为NSObjectenum,其原始值是某些整数类型,例如@objc。您可以在没有这些限制的情况下使用Int查看Swift 1.x代码示例的编辑历史记录。


评论


重要的是,您需要使用@objc注释方法,否则Swift方法将无法从Objective-C中看到。

–汤玛斯·林哈特(TomášLinhart)
2014年6月3日,11:19

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

–汤玛斯·林哈特(TomášLinhart)
2014年6月3日13:48



@MarkusRautopuro-从这里获取:developer.apple.com/library/prerelease/ios/documentation/Swift/…”

–登录
2014年6月3日在16:25



另请参阅:WWDC 2014会议406:将Swift与Objective-C集成

– Stuart M
2014年6月5日7:27

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

–user1021430
2014年11月20日在21:29

#2 楼

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

编译器会自动生成Swift语法来调用C函数和Objective-C方法。如文档中所示,此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 8和OS X v10.10(Yosemite)开发人员库中的所有API参考文档在Objective-C和Swift中都可见形式(例如UIView)。

评论


与Apple文档的直接链接如何将Swift集成到现有项目中:developer.apple.com/library/prerelease/ios/documentation/Swift/…

–skywinder
2014年6月4日11:55



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

–蜂蜜
19年8月11日在12:16



#3 楼

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



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


通过简单的步骤:


出现提示,然后单击“确定...”。不会出现,然后我们按如下所示手动创建它...从iOS源创建一个头文件,并命名为ProjectName-Bridging-Header(例如:Test-Bridging-Header),然后在Swift编译器代码-> Objective-C桥添加Objective-C桥名称..(Test / Test-Bridging-Header.h)。是的,这是完整的。
或者,删除您添加的Objective-C文件(在上面的GIF图像中命名为“ anything”)。您不再需要它。

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

#import "Mixpanel.h"


现在可以在任何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
}


就这样!

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

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


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

#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标头。

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

#6 楼

我想在这里添加一件事:
我非常感谢@Logan的回答。创建桥文件和设置会很有帮助。
但是完成所有这些步骤后,我仍然没有在Swift中获得Objective-C类。
我使用了cocoapods库并将其集成到我的项目。所以是pod "pop"
因此,如果您在Swift中使用Objective-C Pod,则可能无法将类qq1202079q放入Swift。
要做的简单事情是:

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


例如:(弹出库)
替换
#import <pop/POP.h>


@import pop;

@import ObjC_Framework不工作时使用clang import

评论


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

–蜂蜜
16 Dec 2'在3:44

#7 楼

从文档中引用:


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

import Foundation

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


#8 楼

只是为试图向Swift添加Objective-C库的人提供的注释:您应该在Build Settings-> Linking-> Other Linker Flags中添加-ObjC。

评论


为什么?请添加有关此标志的作用以及添加原因的信息。

–约翰·卡尔森(Johan Karlsson)
18/12/21在8:48

#9 楼

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

在下面,您将找到“ Objective-C生成的接口头名称”文件。 br />
将文件导入到视图控制器中。

示例:在我的情况下:“ Dauble-Swift.h”



#10 楼

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

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

#11 楼


从NewFile-> Source->头文件中创建一个.h文件。然后保存文件名Your_Target_Name-Bridging-Header.h。如果两者的名称不同,则项目的目标名称通常相同。
然后在构建设置中搜索“ Objective-C桥接标头”标志并放置新创建的桥接文件的地址,您可以右键单击文件->在finder中显示->将文件拖到文本区域,然后将填充地址。
使用#import Your_Objective-C_file.h

,在swift文件中,您可以访问ObjC文件,但仅使用快速语言。


#12 楼

在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:如果您第一次将新的Objective-C文件添加到Swift项目中时,Xcode会询问您:

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



Step_04:选择选项:

Create Bridging Header

Step_05:将生成一个相应的文件,名称为:

Objc-Bridging-Header.h



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

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

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



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

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





#13 楼

我在github上添加了包含小样本的项目,可以从swift调用Objective C代码。

从swift调用ObjectiveC类

评论


注意:-在swift项目中创建Objc类时,xcode会要求自动桥接该类。别担心 :)

– CrazyPro007
18年5月19日在16:30

#14 楼

洛根答案很好用,除非在最新的Swift 5中它给出了一些编译器错误。这是针对使用Swift 5的人员的修复程序。
Swift 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
    }
}


#15 楼

Swift消费者,Objective-C生产者


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

配置桥接头文件
当看到Would you like to configure an Objective-C bridging header时,单击-是




<target_name>-Bridging-Header.h将自动生成
构建设置-> Objective-C桥接标头


将类添加到桥接标头
<target_name>-Bridging-Header.h中添加一行#import "<MyFileName>.h"

之后,您就可以在MyFileName中使用Objective-C中的Swift

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

Objective-C使用者,Swift生产者


添加<MyFileName>.swift并将NSObject扩展为
将Swift文件导入到ObjC类中
#import "<target_name>-Swift.h"添加到您的Objective-C文件中
通过@objc [@objc和@objcMembers]公开公共Swift代码

之后您可以在Swift中使用Objective-C

#16 楼

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

以下是相关部分:

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

如果您接受,则Xcode会创建桥接头文件以及要创建的文件,并使用产品模块名称后跟“ -Bridging-Header.h”对其进行命名。或者,您可以通过选择File> New> File> [operating system]> Source> Header File来自己创建桥接头文件。编辑桥接头文件以将您的Objective-C代码公开给您的Swift代码:



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

Swift可以看到桥接标头中列出的任何公共Objective-C标头。

#17 楼

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

1


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

2


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

现在好了
感谢

#18 楼

制作NSObject的任何Swift类子类也很有意义,我更喜欢在Objective-C类中使用任何Swift类,例如:
@objc(MySwiftClass)
@objcMembers class MySwiftClass {...}