100

I have an old Objective-C project and I want to call new Swift function and object, I have create the file "<ProjectName>-Bridging-Header.h" and "<ProjectName>-Swift.h"

was easy for me call the function from Swift to Objective-C but I have a problem for reverse.

So I have create a simple class "System.Swift"

import Foundation

@objc class System : NSObject {

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

now I have try to follow the documentation here and inside the <...>-Swift.h file I have write this

@class System;

@interface System : NSObject

-(void)printSome;

@end

and I have import it inside my Objective-C Class. At this point inside my Objective C class (currently UIViewController) of my Objective-C code I have try to call "printSome" method:

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

now I have the following Error:

Undefined symbols for architecture i386: "OBJC_CLASS$_System", referenced from: objc-class-ref in "ObjectiveC_Class_That_Call_Swift_Object".o ld: symbol(s) not found for architecture i386 clang: error: linker command failed with exit code 1 (use -v to see invocation)

pkamb
  • 33,281
  • 23
  • 160
  • 191
Eloreden
  • 1,745
  • 2
  • 12
  • 14
  • You have a linker error. Is it: (1) Xcode uses your product module name—not your target name—when naming the Objective-C bridging header and the generated header for your Swift code, or (2) make sure to import the Objective-C headers for those types prior to importing the Swift generated header into the Objective-C .m file you want to access the Swift code from? Do you have: #import “ProductModuleName-Swift.h” in your Objective-C code? – petert Jun 06 '14 at 09:25
  • Yes i have read the documentation and the name of "ProductModelName" is currect... There is a bug that inside the Build Setting the Product model was not set... i have even set it... – Eloreden Jun 06 '14 at 09:39
  • @petert can you explain better the second point? I wrote everithing i did... – Eloreden Jun 06 '14 at 10:11
  • Problem Solved, i have add a new .h file in my project call -Swift.h but this is not necessary because the compiler just create this object even if i can't see it. I have delete the new file that i have create and now all run perfectly. Tnx petert – Eloreden Jun 06 '14 at 10:46
  • You can answer your own questions - it might help others. – petert Jun 06 '14 at 15:24
  • I know it's a really old question, but the title is misleading. You are trying to call a method, not a function. – SPQR3 Nov 06 '20 at 11:37

9 Answers9

65

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
Top-Master
  • 7,611
  • 5
  • 39
  • 71
Svitlana
  • 2,938
  • 1
  • 29
  • 38
  • You can also override the Obj-C name of your Swift class using `@objc (MyClassName)` – nielsbot Dec 23 '14 at 08:50
  • 16
    For anyone who may do same dumb mistake as me. In step 2, make sure you use `(ProjectName)-Swift.h`, **NOT** `(ClassName)-Swift.h` ! – Hlung Jul 28 '15 at 17:01
  • thanks @Svitlana, unbelievable, it worked!!! But I have to retry many times these steps, including moving my added methods to other places in the class. – Scofield Tran Jan 05 '16 at 08:04
  • 1
    `3) @class SwiftClassName;` saved me – Mazen Kasser Sep 04 '19 at 05:25
  • if your target name has any `spaces` add "_" (underscores instead of spaces) when creating swift.h import eg: if your target name is `Sample App` then your import statement would be `#import "Sample_App-Swift.h"` – Rakshitha Muranga Rodrigo Jul 25 '21 at 14:28
  • I hope it helped lots of people, but this is the most inconsistent but accepted answer I have every seen – Trident Nov 23 '21 at 19:44
62

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.

Patru
  • 4,481
  • 2
  • 32
  • 42
Eloreden
  • 1,745
  • 2
  • 12
  • 14
  • 3
    how about functions with parameters? – Arnlee Vizcayno Sep 17 '14 at 09:04
  • 3
    I am not able to access Swift functions with parameters and a return value, nor I am able to access Swift Functions without parameters and without a return value. I don't know why. My Swift Class is an NSObject, I imported the Foundation framework, the class and the functions have the `@objc` prefix. The `-Swift.h` has been automatically created. The thing that is making me headache is that I can call the Class itself but not any function inside it. Does anyone know why? – David Gölzhäuser Sep 20 '14 at 18:15
  • 6
    good example at http://ericasadun.com/2014/08/21/swift-calling-swift-functions-from-objective-c/ – Paul Beusterien Oct 29 '14 at 01:04
  • 3
    It is `-.Swift.h` (not `model`). – SwiftArchitect Sep 13 '15 at 19:49
  • 3
    If your Product name has any spaces in it, replace them with underscores, like: `#import "My_Project-Swift.h"`. – EricRobertBrewer Sep 06 '16 at 19:14
  • 1
    Note if the header name isn't obvious, you can look in your project build settings for 'Objective-C Generated Interface header name' – Confused Vorlon Nov 08 '18 at 15:45
36

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];

Avijit Nagare
  • 8,482
  • 7
  • 39
  • 68
Anubhav Giri
  • 517
  • 4
  • 7
12

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.

Darius Miliauskas
  • 3,391
  • 4
  • 35
  • 53
6

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 {

Kqtr
  • 5,824
  • 3
  • 25
  • 32
2

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.

Bryan P
  • 4,142
  • 5
  • 41
  • 60
1

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.

0

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>
Farhad Malekpour
  • 1,314
  • 13
  • 16
-3

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.
Trident
  • 810
  • 9
  • 20
  • 1
    Whilst this may theoretically answer the question, [it would be preferable](//meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Arghya Sadhu Sep 04 '20 at 16:45