Setting up Swift and Objective-C Interoperability

As Swift becomes more widely used the question arises: how to integrate the this new language and functionality with established objective-c code bases. Here I will explain how to integrate Swift and objective-c classes in a single project.

Doing so might seem like a treacherous maneuver. But by following a few simple steps, you can set up your project to Swift and objective-c interoperability with perfect ease.

A few things before getting started

From here on out I will assume you know the basics of developing an iOS app using Xcode and are familiar with Objective-C and Swift.

If you need help setting up a Swift project I recommend this tutorial by Ray Wenderlich to get started: https://www.raywenderlich.com/115253/swift-2-tutorial-a-quick-start. Or if you are a complete beginner, this is another Swift tutorial that moves at a slower pace: https://www.raywenderlich.com/114148/learn-to-code-ios-apps-with-swift-tutorial-1-welcome-to-programming.

If you need help setting up a standard Xcode project in Objective-C, this is a good tutorial to help you get familiar with the basics: http://codewithchris.com/xcode-tutorial/.

Make a Swift Class available to Objective-C Files

To access and use swift classes or libraries in objective-c files start with an objective-c project that already contains some files.

  1. Add a new Swift file to the project. In the menu select File>New>File… then select Swift File, instead of Cocoa Touch Class. Name the file and hit create.
  2. A dialogue box will appear, make sure to select “Create Bridging Header” when prompted. The first time you add a swift file to your project is the only time this prompt will appear. Selecting Create Bridge Header right away will save you the trouble of creating it manually.

If you do need to create in manually, this link should help you do that: http://www.learnswiftonline.com/getting-started/adding-swift-bridging-header/.

3. Next, after selecting “Create Bridging Header” or creating it manually, go to your project’s general settings. Select the proper target for your app. Go to “Build Settings” and switch to “All”, instead of “Basic” which is the default. Here search for the “Packaging” section. Turn on “Defines Module”, by changing “No” to “Yes”.

When this is turned on we will now be able to use swift classes inside of objective-c files.

4. Before leaving the “Build Settings” look for “Product Module Name” in the “Packaging” section. This will be important so make sure to take note of and copy the “Product Module Name” exactly.

5. Next go to an objective-c class where you would like to be able to have access to your swift class. In the implementation or .m file of this class import a header like this:

#import "MyProjectModuleName-Swift.h"

Here the file name of the import must be the exact Project Module Name from the build settings. Any objective-c file where you want access to your swift class should include this import.

6. Now it is worth mentioning one potential issue that may arise when using a swift class. Objective-c cannot read top-level swift classes. So if you go to use a method or variable from your swift class directly it will not be recognized. There are two simple solutions to this issue. First, add @objc before the class declaration in the swift file. This will make the class visible and usable in the objective-c file.

@objc public class myClass

Or, second, subclass the swift class from NSObject:

public class myClass: NSObject {
}

Either of these will quickly solve the issue.

Congratulations! Now you have access to swift classes in any objective-c file you choose!!

Note: Under the hood when the special “MyProjectModuleName-Swift” class is created Xcode automatically puts objective-c versions of the swift files into the implementation of this header so that they can coordinate with your objective-c files.

Make an Objective-C class available in Swift Files

Now to make objective-C code available in a Swift class follow these steps:

  1. Make an objective-c class that you wish to use in a swift file. When you add a new objective-c class to a swift project you will be prompted with a message asking if you would like to create the Bridging Header (as mentioned above). Make sure to answer yes to create the Bridging Header or create it manually.
  2. Once you have created the Bridging Header file, go to it in the files list in the Navigator Area of Xcode.

3. Here add the import headers of the objective-c classes you wish to use in your swift classes. Once you include a header in the Bridging header file, there is no need to reimport it into any Swift file. It is accessible across all swift files in the project.

Now your selected objective-c objects are available to your swift classes!! Well done!!

Things to Keep in Mind when using Swift and Objective-C

Swift and Objective-C have some fundamental differences and there are some very important things to keep in mind when working across the two languages. In order to have the smoothest transition from one language to the other, it’s best to keep in mind their unique abilities and functionality.

Differences between Swift and Objective-C

If a method or variable from a swift class doesn’t show up in your objective-c file it is likely because objective-c does not support a particular feature that determines that method or variable.

Here is a short list of Swift features that are not available in objective-c: tuples, generics, any global variables, structs, typealiases, or enums defined in swift, and the top-level swift functions.

One way to deal with this is make a wrapper class that can process these unavailable features and be called when talking to the objective-c classes.

Subclassing Limitation

One limitation is the inability to subclass from swift. Swift objects can have a subclass of an objective-c class, like NSObject. But a swift class cannot be a base class for an objective-c class.

Types

Luckily, objective-C types and swift types correspond well to each other and translate well across languages.

From www.natashatherobot.com

Optionals

Optional status is a very important difference in functionality between objective-c and Swift. When you pass arguments to your swift classes from objective-c, swift must know the variable’s optional status. In Swift, nothing can be left undefined and potentially nil. Since objective-c doesn’t share this requirement, the passed in argument might automatically be followed by a ! or bang symbol, or other worse problems and bugs can occur. Ideally, you should set up some way to check each variable that is being passed in to swift for it’s optional status.

One preliminary measure you can take when passing properties to swift is to state nonnull or nullable from the beginning in the objective-c class file.

@property (nonatomic, strong, nonnull) NSString *name;

This lets the swift file know that this variable will not be null when received. As a short cut, you can also specify that an entire file is nonnull or nullable. Add the following line before the @interface of a file.

NS_ASSUME_NONNULL_BEGIN

Then add the next line after the @end.

NS_ASSUME_NONNULL_END

Thank you for reading!

Helpful links and sources: