Swift: Calling Swift functions from Objective-C

It’s a lot easier than the docs make it out to be, especially if you’re just using a single target. Here’s my Swift file. Make sure you use the @objc keyword to tag your Swift classes so they’re available to your ObjC ones.

import Foundation

@objc class TestClass {
    class func `new`() -> TestClass {
        return TestClass()
    }
    
    func testFunction() {
        println("This function works")
    }
}

And here’s the Objective-C client:

#import "AppDelegate.h"
#import "TestProject-Swift.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application 
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    TestClass *instance = [TestClass new];
    [instance testFunction];
    return YES;
}
@end

The secret here is to import the name of the target in this case “TestProject” with the “-Swift.h” extension. Xcode builds this for you and hides it behind the scenes in the derived data. For the above example, mine was left at: DerivedData/TestProject-aqpeqeuqusyzdtcqddjdixoppyqn/Build/Intermediates/TestProject.build/Debug-iphoneos/TestProject.build/DerivedSources/TestProject-Swift.h

The .h file is actually quite interesting. Here is the interface that was built from my Swift code:

SWIFT_CLASS("_TtC11TestProject9TestClass")
@interface TestClass
+ (TestClass *)new;
- (void)testFunction;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

There’s also a bit of fascinating cookiecutter set-up to be found in the header file. I encourage you to take a peek.

4 Comments

  • […] Calling Swift from C. […]

  • Thanks! One thing that confused me for awhile is that “TestProject-Swift.h” (and its declarations) are unrecognized until after the first build.

  • Thanks – one thing I noticed it is the $PRODUCT_NAME of your Target – not just the name of your Target ( this confused me for a bit )

  • the class doesn’t show up with NSClassFromString(), however –
    any idea about that?