How do I call Objective-C code from Swift?

i0S Swift Issue

Question or problem with Swift language programming:

In Swift, how does one call Objective-C code?

Apple mentioned that they could co-exist in one application, but does this mean that one could technically re-use old classes made in Objective-C whilst building new classes in Swift?

How to solve the problem:

Solution 1:

Using Objective-C Classes in Swift


If you have an existing class that you’d like to use, perform Step 2 and then skip to Step 5. (For some cases, I had to add an explicit #import

Step 1: Add Objective-C Implementation — .m

Add a .m file to your class, and name it CustomObject.m.

Step 2: Add Bridging Header

When adding your .m file, you’ll likely be hit with a prompt that looks like this:

A macOS sheet-style dialog from Xcode asking if you would "like to configure an Objective-C bridging header"

Click Yes!

If you did not see the prompt, or accidentally deleted your bridging header, add a new .h file to your project and name it <#YourProjectName#>-Bridging-Header.h.

In some situations, particularly when working with Objective-C frameworks, you don’t add an Objective-C class explicitly and Xcode can’t find the linker. In this case, create your .h file named as mentioned above, then make sure you link its path in your target’s project settings like so:

An animation demonstrating the above paragraph

Note:

It’s best practice to link your project using the $(SRCROOT) macro so that if you move your project, or work on it with others using a remote repository, it will still work. $(SRCROOT) can be thought of as the directory that contains your .xcodeproj file. It might look like this:

$(SRCROOT)/Folder/Folder/<#YourProjectName#>-Bridging-Header.h
Step 3: Add Objective-C Header — .h

Add another .h file and name it CustomObject.h.

Step 4: Build your Objective-C Class

In CustomObject.h

#import 

@interface CustomObject : NSObject

@property (strong, nonatomic) id someProperty;

- (void) someMethod;

@end

In CustomObject.m

#import "CustomObject.h"

@implementation CustomObject 

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

@end
Step 5: Add Class to Bridging-Header

In YourProject-Bridging-Header.h:

#import "CustomObject.h"
Step 6: Use your Object

In SomeSwiftFile.swift:

var instanceOfCustomObject = CustomObject()
instanceOfCustomObject.someProperty = "Hello World"
print(instanceOfCustomObject.someProperty)
instanceOfCustomObject.someMethod()

There is no need to import explicitly; that’s what the bridging header is for.

Using Swift Classes in Objective-C

Step 1: Create New Swift Class

Add a .swift file to your project, and name it MySwiftObject.swift.

In MySwiftObject.swift:

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)"
    }
}
Step 2: Import Swift Files to ObjC Class

In SomeRandomClass.m:

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

The file:<#YourProjectName#>-Swift.h should already be created automatically in your project, even if you can not see it.

Step 3: Use your class
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);
Notes:
  1. If Code Completion isn’t behaving as you expect, try running a quick build with R to help Xcode find some of the Objective-C code from a Swift context and vice versa.

  2. If you add a .swift file to an older project and get the error dyld: Library not loaded: @rpath/libswift_stdlib_core.dylib, try completely restarting Xcode.

  3. While it was originally possible to use pure Swift classes (Not descendents of NSObject) which are visible to Objective-C by using the @objc prefix, this is no longer possible. Now, to be visible in Objective-C, the Swift object must either be a class conforming to NSObjectProtocol (easiest way to do this is to inherit from NSObject), or to be an enum marked @objc with a raw value of some integer type like Int. You may view the edit history for an example of Swift 1.x code using @objc without these restrictions.

Solution 2:

See Apple’s guide to Using Swift with Cocoa and Objective-C. This guide covers how to use Objective-C and C code from Swift and vice versa and has recommendations for how to convert a project or mix and match Objective-C/C and Swift parts in an existing project.

The compiler automatically generates Swift syntax for calling C functions and Objective-C methods. As seen in the documentation, this Objective-C:

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

turns into this Swift code:

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

Xcode also does this translation on the fly — you can use Open Quickly while editing a Swift file and type an Objective-C class name, and it’ll take you to a Swift-ified version of the class header. (You can also get this by cmd-clicking on an API symbol in a Swift file.) And all the API reference documentation in the iOS 8 and OS X v10.10 (Yosemite) developer libraries is visible in both Objective-C and Swift forms (e.g. UIView).

Solution 3:

Here are step-by-step instructions for using Objective-C code (in this case, a framework provided by a third-party) in a Swift project:

  1. Add any Objective-C file to your Swift project by choosing File -> New -> New File -> Objective-C File. Upon saving, Xcode will ask if you want to add a bridging header. Choose ‘Yes‘. Gif: adding empty file to project and generating bridging header
    (source: derrrick.com)

In simple steps:

  1. A prompt appears, and then click on OK… If it does not appear, then we create it manually like in the following… Create one header file from iOS source and give the name ProjectName-Bridging-Header (example: Test-Bridging-Header), and then go to build setting in the Swift compiler code -> Objective-C bridge add Objective-C bridge name ..(Test/Test-Bridging-Header.h). Yeah, that’s complete.

  2. Optionally, delete the Objective-C file you added (named “anything” in the GIF image above). You don’t need it any more.

  3. Open the bridging header file — the filename is of the form [YourProject]-Bridging-Header.h. It includes an Xcode-provided comment. Add a line of code for the Objective-C file you want to include, such as a third-party framework. For example, to add Mixpanel to your project, you will need to add the following line of code to the bridging header file:

    #import "Mixpanel.h"
  4. Now in any Swift file you can use existing Objective-C code, in the Swift syntax (in the case of this example, and you can call Mixpanel SDK methods, etc.). You need to familiarize yourself with how Xcode translates Objective-C to Swift. Apple’s guide is a quick read. Or see this answer for an incomplete summary.

Example for Mixpanel:

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

That’s it!

Note: If you remove the bridging header file from your project, be sure to go into Build Settings and remove the value for “Objective-C Bridging Header” under “Swift Compiler – Code Generation”.

Solution 4:

You can read the nice post Swift & Cocoapods. Basically, we need to create a bridging header file and put all Objective-C headers there. And then we need to reference it from our build settings. After that, we can use the Objective-C code.

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

Also have a look at Apple’s document Using Swift with Cocoa and Objective-C as well.

Solution 5:

I wrote a simple Xcode 6 project that shows how to mix C++, Objective-C and Swift code:

https://github.com/romitagl/shared/tree/master/C-ObjC-Swift/Performance_Console

In particular, the example calls an Objective-C and a C++ function from the Swift.

The key is to create a shared header, Project-Bridging-Header.h, and put the Objective-C headers there.

Please download the project as a complete example.

Hope this helps!