从 Objective-C 类调用 Swift 函数

我有一个旧的 Objective-C 项目,我想调用新的 Swift 函数和对象,我已经创建了文件“ <ProjectName>-Bridging-Header.h”和“ <ProjectName>-Swift.h

对我来说调用从 Swift 到 Objective-C 的函数很容易,但是我有一个反向的问题。

所以我创建了一个简单的类“ System. Swift”

import Foundation


@objc class System : NSObject {


@objc func printSome() {
println("Print line System");
}
    

}

现在我已经尝试按照文档 给你和在 <...>-Swift.h文件中我已经写了这一点

@class System;


@interface System : NSObject


-(void)printSome;


@end

我把它导入到我的 Objective-C 类中。此时,在 Objective-C 代码的 Objective C 类(目前是 UIViewController)中,我尝试调用“ printSome”方法:

- (void)viewDidLoad
{
[super viewDidLoad];
System * sis = [[System alloc] init];
[sis printSome];
//any additional setup after loading the view from its nib.
}

现在我有以下错误:

架构 i386的未定义符号: “ OBJC _ CLASS $_ System”, 引自: “ ObjectiveC _ Class _ That _ Call _ Swift _ Object”中的 objecc-class-ref. o ld: 在体系结构 i386中找不到符号 clang: error: linker 命令失败,退出代码1(使用 -v 查看调用)

121398 次浏览

Problem Solved, I previously create and included a new .h file in my Objective-C class named <ProductModuleName>-Swift.h but, as i discovered later, this step is not necessary because the compiler creates the necessary file invisible.

Simply include <ProductModuleName>-Swift.h in your class and it should work.

It is strange but will work after we do:

  1. Add @objc to your Swift-class ("MySwiftClass").

  2. Add in Obj-C, i.e. the .m file:

    #import "(ProjectName)-Swift.h"
    
  3. Declare in header .h

    @class MySwiftClass;
    

Compiler will generate the interface for @objc marked class in MyModuleName-Swift.h file.

Auto-Generated Obj-C Example:

SWIFT_CLASS("_TtC10Project17220PLHelper")
@interface PLHelper


+ (void)notifyForDownloading:(NSDictionary *)userInfo;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

Check the -Swift.h file which has the import on your .m file in objective-C:

#import <YourProjectName-Swift.h>

Click on that line, and left-click - Jump To Definition.

This file should be included automatically, not manually.

Assume We have ProjectName "MyFirstProjectOnSwift" and swift class name "mySwiftClass" and objectiveC class is "MyObjectiveCLass"

Following steps are:-

  1. Add #import "MyFirstProjectOnSwift-Swift.h" in "MyObjectiveCLass.m"

  2. Add @class mySwiftClass in MyObjectiveCLass.h;

  3. Then in MyObjectiveCLass.m

    mySwiftClass *myClass = [mySwiftClass new]; {Call Like This in any method wherever you want to call swift method.}

  4. [myClass methodName];

If you're still not seeing your class even after importing <ProductModuleName>-Swift.h.

Make sure that your class is subclassing a native class (e.g UIViewController) or at least if it's just a utility class, make it subclass NSObject. Your class should now show.

Little additional tip for anyone stumbling upon this post and for hwhom the other answers do not work: you might also have to declare your Swift class "public".

Example:

@objc public class MySwiftClass: NSObject {

The recomended way for executing Swift code from Objective-C on projects that are being migrated from Obj-C to Swift is using Bridge/Proxy pattern.

  1. Implement the Bridge.

import Foundation

@objc class AnalyticsPropertyBridge: NSObject {

private var analytics: AnalyticsManager = AnalyticsManager()


@objc func refreshProperties() {


self.analytics.set(AnalyticsProperty.clientType)
}

}

  1. Include the objC caller module in the umbrella file (Bridging-Header):

#import "CallerModule.h"

  1. Finally in the caller .m file, two issues:

3.a Import umbrella file:

#import "MyProject-Swift.h"

3.b Call the bridge.

[[AnalyticsPropertyBridge new] refreshProperties];

Benefits: Your swift code will not get dirty with @objc because code is being called from Objc. As time goes by, the ObjC will be reduced in your project and finally the bride will be removed.

A good article out here if someone still having issues.

Setting up Swift and Objective-C Interoperability

  1. This article discusses in-depth how to import Swift files into ObjC as well as Objc files to Swift.
  2. It also addresses a problem generally faced when the Project name has space in it.
  3. It also discusses about “Product Module Name” flag.

A note about project name, if there are spaces in project name make sure you replace them with underscore, for example if project name is "My Project" you need to include:

#import <My_Project-Swift.h>