如何从swift调用objective-c代码

How to call Objective-C code from Swift

在苹果新推出的Swift语言中,如何称之为Objective-C代码?

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

推理

Objective-C是一种独立于平台的语言,而Swift则依赖于平台。因此,用swift编写非平台依赖代码(业务逻辑库)是不明智的。但是,在其中编写依赖于平台的代码(例如,与接口相关的代码)将是非常好的。不说这是个好主意,但它绝对是一种兴趣。


在swift中使用objective-c类

**如果您有一个要使用的现有类,请执行步骤2,然后跳到步骤5。(对于某些情况,我必须在旧的Objective-C文件中添加一个明确的#import )。**

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

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

步骤2:添加桥接头

添加.m文件时,可能会出现如下提示:

Enter image description here

单击"是"!

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

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

Enter image description here

注释

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

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

步骤3:添加objective-c头--.h

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

第4步:建立目标C类

CustomObject.h

1
2
3
4
5
6
7
8
9
#import <Foundation/Foundation.h>

@interface CustomObject : NSObject

@property (strong, nonatomic) id someProperty;

- (void) someMethod;

@end

CustomObject.m

1
2
3
4
5
6
7
8
9
#import"CustomObject.h"

@implementation CustomObject

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

@end

步骤5:向桥接头添加类

YourProject-Bridging-Header.h中:

1
#import"CustomObject.h"

第六步:使用你的物品

SomeSwiftFile.swift中:

1
2
3
4
var instanceOfCustomObject: CustomObject = CustomObject()
instanceOfCustomObject.someProperty ="Hello World"
println(instanceOfCustomObject.someProperty)
instanceOfCustomObject.someMethod()

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

在Objective-C中使用Swift类步骤1:创建新的swift类

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

MySwiftObject.swift中:

1
2
3
4
5
6
7
8
9
10
11
12
13
import Foundation

class MySwiftObject : NSObject {

    var someProperty: AnyObject ="Some Initializer Val"

    init() {}

    func someFunction(someArg:AnyObject) -> String {
        var returnVal ="You sent me \(someArg)"
        return returnVal
    }  
}

步骤2:将swift文件导入objc类

SomeRandomClass.m中:

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

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

第三步:使用你的课程

1
2
3
4
5
6
7
8
9
10
11
MySwiftObject * myOb = [MySwiftObject new];
NSLog(@"MyOb.someProperty: %@", myOb.someProperty);
myOb.someProperty = @"Hello World";
NSLog(@"MyOb.someProperty: %@", myOb.someProperty);

// original
NSString * retString = [myOb someFunction:@"Arg"];
// xcode10 expands the external arg here
NSString * retString = [myOb someFunctionWithSomeArg:@"Arg"];|

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

注:

1。codeCompletion的行为没有我想的那么准确。在我的系统中,使用"cmd+r"运行一个快速构建似乎有助于swift找到一些objective-c代码,反之亦然。

2。如果向旧项目添加一个.swift文件并得到错误:dyld: Library not loaded: @rpath/libswift_stdlib_core.dylib,请尝试完全重新启动xcode。

三。虽然最初可以通过使用@objc前缀在objective-c中使用纯swift类,但在swift 2.0之后,这已经不可能了。有关原始解释,请参见编辑历史记录。如果在未来的Swift版本中重新启用此功能,答案将相应更新。


参见苹果公司的Cocoa和Objective-C使用Swift的指南。本指南涵盖了如何使用Swift的Objective-C和C代码,反之亦然,并对如何转换项目或混合和匹配现有项目中的Objective-C/C和Swift部件提出了建议。

编译器自动生成用于调用C函数和Objective-C方法的Swift语法。如文件所示,本目标-C:

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

变成这个swift代码:

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

Xcode还可以动态地进行这种翻译——您可以在编辑Swift文件的同时快速使用open,并键入objective-c类名,它将带您进入类头的Swift-ified版本。(您也可以通过命令单击Swift文件中的API符号来获取此信息。)iOS 8和OS X v10.10(Yosemite)开发人员库中的所有API参考文档都以Objective-C和Swift格式(如UIView显示。


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

  • 通过选择文件->新建->新建文件->目标C文件,将任何目标C文件添加到Swift项目中。保存后,Xcode将询问是否要添加桥接头。选择"是"。GIF:向项目添加空文件并生成桥接头http://www.derrrick.com/stackoverflow/1-empty-file.gif
  • 简单步骤:

  • 出现提示,然后单击确定…如果它没有出现,那么我们手动创建它,如下所示…从iOS源创建一个头文件,并将名称命名为projectname bridging header(例如:test bridging header),然后转到swift编译器代码中的build setting->objective-c bridge add objective-c bridge name..(test/test bridging header.h)。是的,已经完成了。

  • 或者,删除您添加的objective-c文件(在上面的gif图像中命名为"anything")。你不再需要它了。

  • 打开桥接头文件——文件名的格式为[yourproject]-bridging header.h。它包括xcode提供的注释。为要包含的目标C文件添加一行代码,例如第三方框架。例如,要将mixpanel添加到项目中,需要将以下代码行添加到桥接头文件中:

    1
    #import"Mixpanel.h"
  • 现在,在任何swift文件中,您都可以使用现有的objective-c代码和swift语法(在本例中,您可以调用mixpanel-sdk方法等)。您需要熟悉Xcode如何将Objective-C转换为Swift。苹果的指南很快就能读完。或查看此答案获取不完整的摘要。

  • 混合面板示例:

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

    就是这样!

    注意:如果从项目中移除桥接头文件,请确保进入构建设置并移除"swift compiler-code generation"下的"objective-c桥接头"值。


    您可以阅读"雨燕"和"可可豆"的贴子。基本上,我们需要创建一个桥接头文件,并将所有Objective-C头放在那里。然后我们需要从构建设置中引用它。之后,我们可以使用Objective-C代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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的文档。


    我写了一个简单的XCODE 6项目,展示了如何混合C++、ObjuleC和SWIFT代码:

    https://github.com/romitagl/shared/tree/master/c-objc-swift/performance_控制台

    特别是,该示例调用SWIFT C和C++函数。

    关键是创建一个共享头文件projectbridgingheader.h,并将objective-c头文件放在那里。

    请下载这个项目作为一个完整的例子。


    引用文件:

    Any Objective-C framework (or C library) that’s accessible as a module
    can be imported directly into Swift. This includes all of the
    Objective-C system frameworks—such as Foundation, UIKit, and
    SpriteKit—as well as common C libraries supplied with the system. For
    example, to import Foundation, simply add this import statement to the
    top of the Swift file you’re working in:

    import Foundation

    This import makes all of the Foundation APIs—including NSDate, NSURL,
    NSMutableData, and all of their methods, properties, and
    categories—directly available in Swift.


    我想在这里再加一件事:

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

    但在完成所有这些步骤之后,我仍然没有在Swift上获得一个客观的C类课程。

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

    因此,如果您在swift中使用的是objective-c pods,那么您可能无法获得或无法将ecx1(2)类转换为swift。

    你要做的简单的事情是:

  • 转到-Bridging-Header文件,然后
  • 将声明#import 替换为@import ObjC_Framework
  • 例如:(pop库)

    替换

    1
    #import <pop/POP.h>

    具有

    1
    @import pop;

    #import不工作时,使用clang import


    对于试图向swift添加objective-c库的人来说,这只是一个说明:您应该在build settings->linking->other linker flags中添加-objc。


    创建桥接头之后,转到构建设置=>搜索"Objective-C桥接头"。

    下面是"Objective-C生成的接口头文件名"。

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

    例如:在我的例子中:"dauble swift.h"

    eEter image description here


    单击新建文件菜单,然后选择文件选择语言目标。这时,它自动生成一个"objective-c桥接头"文件,用于定义一些类名。

    "swift编译器-代码生成"下的"objective-c桥接头"。


    enter image description here我在Github上添加了一个项目,其中包括从Swift调用目标C代码的小样本。

    从swift调用objectec类


  • 从newfile->source->header file创建.h文件
  • 然后将文件名保存到您的目标文件名-桥接头.h这里的人通常会错误地使用他们的项目名,但如果两者都不相同,那么应该是项目的目标文件名。
  • 然后在build settings中搜索objective-c桥接头标记并放置新创建的桥接文件的地址,您可以右键单击文件->在finder中显示->在文本区域中拖动该文件,然后填充该地址。
  • 使用导入目标文件.h
  • 在swift文件中,您可以访问objc文件,但只能使用swift语言。

  • 在Xcode10.1中的swift 4.2.1项目中,您可以轻松地添加objective-c文件。按照以下步骤将目标C文件连接到Swift项目。

    步骤U 01:使用Swift语言创建新的Xcode项目:

    File>New>Project>objc

    步骤:在Swift项目中添加新的目标C文件:

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

    步骤:如果您第一次在Swift项目中添加新的Objective-C文件,Xcode会要求您:

    EDOCX1?9?

    enter image description here

    步骤04:选择选项:

    Create Bridging Header

    步骤:将生成具有以下名称的相应文件:

    Objc-Bridging-Header.h

    enter image description here

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

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

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

    enter image description here

    步骤08:打开你的Objc-Bridging-Header.h文件,导入你想在swift文件中使用的objective-c文件。

    1
    #import"SpecialObjcFile.m"

    以下是SpecialObjcFile.m的内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #import <Foundation/Foundation.h>

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

    步骤09:现在在您的swift文件中,您可以使用Objective-C类:

    1
    2
    3
    4
    5
    override func viewDidLoad() {
        super.viewDidLoad()
        let myObjcContent = Person()
        print(myObjcContent.busy)
    }

    enter image description hereenter image description here


    苹果公司在本文件中提供了官方指南:如何呼叫-目标-C-代码-来自-swift

    相关部分如下:

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

    如果您接受,xcode将创建桥接头文件以及您正在创建的文件,并使用产品模块名,后跟"-bridging header.h"对其进行命名。或者,您可以通过选择文件>新建>文件>操作系统>源>头文件自己创建桥接头文件。

    编辑桥接头以将目标C代码公开到您的swift代码:

  • 在您的objective-c桥接头中,导入要向swift公开的每个objective-c头。
  • 在构建设置中,在swift编译器代码生成中,确保objective-c桥接头构建设置具有桥接头文件的路径。路径应该与项目相关,类似于在生成设置中指定info.plist路径的方式。在大多数情况下,您不需要修改此设置。
  • swift可以看到桥接头中列出的任何公共Objective-C头段。


    使用Objective-C的双向方法Objective-C

  • 在Xcode项目中创建bridge header.h文件
  • 在桥头文件中导入.h文件
  • 在生成设置中设置桥头的路径。
  • 清理项目
  • 在Project中创建Objective-C文件(它会自动为您设置构建设置中的路径)
  • 在桥头文件中导入.h文件
  • 现在好去谢谢