iOS Developer Library — Prerelease

Developer

Using Swift with Cocoa and Objective-C

iBooks
On This Page

Swift and Objective-C in the Same Project

Swift’s compatibility with Objective-C lets you create a project that contains files written in either language. You can use this feature, called mix and match, to write apps that have a mixed-language codebase. Using mix and match, you can implement part of your app’s functionality using the latest Swift features and seamlessly incorporate it back into your existing Objective-C codebase.

Mix and Match Overview

Objective-C and Swift files can coexist in a single project, whether the project was originally an Objective-C or Swift project. You can simply add a file of the other language directly to an existing project. This natural workflow makes creating mixed-language app and framework targets as straightforward as creating an app or framework target written in a single language.

The process for working with mixed-language targets differs slightly depending on whether you’re writing an app or a framework. The general import model for working with both languages within the same target is depicted below and described in more detail in the following sections.

image: ../Art/DAG_2x.png

Importing Code from Within the Same App Target

If you’re writing a mixed-language app, you may need to access your Objective-C code from Swift and your Swift code from Objective-C. The process described in this section applies to non-framework targets.

Importing Objective-C into Swift

To import a set of Objective-C files in the same app target as your Swift code, you rely on an Objective-C bridging header to expose those files to Swift. Xcode offers to create this header file when you add a Swift file to an existing Objective-C app, or an Objective-C file to an existing Swift app.

image: ../Art/bridgingheader_2x.png

If you accept, Xcode creates the header file along with the file you were creating, and names it by your product module name followed by adding "-Bridging-Header.h". (You’ll learn more about the product module name later, in Naming Your Product Module.)

Alternatively, you can create a bridging header yourself by choosing File > New > File > (iOS or OS X) > Source > Header File.

You’ll need to edit the bridging header file to expose your Objective-C code to your Swift code.

To import Objective-C code into Swift from the same target

  1. In your Objective-C bridging header file, import every Objective-C header you want to expose to Swift. For example:

    1. #import "XYZCustomCell.h"
    2. #import "XYZCustomView.h"
    3. #import "XYZCustomViewController.h"
  2. Under Build Settings, make sure the Objective-C Bridging Header build setting under Swift Compiler - Code Generation has a path to the header.

    The path should be relative to your project, similar to the way your Info.plist path is specified in Build Settings. In most cases, you should not need to modify this setting.

Any public Objective-C headers listed in this bridging header file will be visible to Swift. The Objective-C functionality will be available in any Swift file within that target automatically, without any import statements. Use your custom Objective-C code with the same Swift syntax you use with system classes.

  1. let myCell = XYZCustomCell()
  2. myCell.subtitle = "A custom cell"

Importing Swift into Objective-C

When you import Swift code into Objective-C, you rely on an Xcode-generated header file to expose those files to Objective-C. This automatically generated file is an Objective-C header that declares the Swift interfaces in your target. It can be thought of as an umbrella header for your Swift code. The name of this header is your product module name followed by adding "-Swift.h". (You’ll learn more about the product module name later, in Naming Your Product Module.)

By default, the generated header contains interfaces for Swift declarations marked with the public modifier. It also contains those marked with the internal modifier if your app target has an Objective-C bridging header. Declarations marked with the private modifier do not appear in the generated header. Private declarations are not exposed to Objective-C unless they are explicitly marked with @IBAction, @IBOutlet, or @objc as well. If your app target is compiled with testing enabled, a unit test target can access any declaration with the internal modifier as if they were declared with the public modifier by prepending @testable to the product module import statement.

For more information on access-level modifiers, see Access Control in The Swift Programming Language.

You don’t need to do anything special to create the generated header file—just import it to use its contents in your Objective-C code. Note that the Swift interfaces in the generated header include references to all of the Objective-C types used in them. If you use your own Objective-C types in your Swift code, make sure to import the Objective-C headers for those types before importing the Swift generated header into the Objective-C .m file you want to access the Swift code from.

To import Swift code into Objective-C from the same target

  • Import the Swift code from that target into any Objective-C .m file within that target using this syntax and substituting the appropriate name:

    1. #import "ProductModuleName-Swift.h"

The Swift files in your target will be visible in Objective-C .m files containing this import statement. For information on using Swift from Objective-C code, see Using Swift from Objective-C.

Import into Swift

Import into Objective-C

Swift code

No import statement

#import "ProductModuleName-Swift.h"

Objective-C code

No import statement; Objective-C bridging header required

#import "Header.h"

Importing Code from Within the Same Framework Target

If you’re writing a mixed-language framework, you may need to access your Objective-C code from Swift and your Swift code from Objective-C.

Importing Objective-C into Swift

To import a set of Objective-C files in the same framework target as your Swift code, you’ll need to import those files into the Objective-C umbrella header for the framework.

To import Objective-C code into Swift from the same framework

  1. Under Build Settings, in Packaging, make sure the Defines Module setting for that framework target is set to Yes.

  2. In your umbrella header file, import every Objective-C header you want to expose to Swift. For example:

    1. #import <XYZ/XYZCustomCell.h>
    2. #import <XYZ/XYZCustomView.h>
    3. #import <XYZ/XYZCustomViewController.h>

Swift will see every header you expose publicly in your umbrella header. The contents of the Objective-C files in that framework will be available in any Swift file within that framework target automatically, without any import statements. Use your custom Objective-C code with the same Swift syntax you use with system classes.

  1. let myOtherCell = XYZCustomCell()
  2. myOtherCell.subtitle = "Another custom cell"

Importing Swift into Objective-C

To import a set of Swift files in the same framework target as your Objective-C code, you don’t need to import anything into the umbrella header for the framework. Instead, import the Xcode-generated header file for your Swift code into any Objective-C .m file you want to use your Swift code from.

Because the generated header for a framework target is part of the framework’s public interface, only declarations marked with the public modifier appear in the generated header for a framework target. You can still use Swift methods and properties that are marked with the internal modifier from within the Objective-C part of your framework, as long they are declared within a class that inherits from an Objective-C class. For more information on access-level modifiers, see Access Control in The Swift Programming Language.

To import Swift code into Objective-C from the same framework

  1. Under Build Settings, in Packaging, make sure the Defines Module setting for that framework target is set to Yes.

  2. Import the Swift code from that framework target into any Objective-C .m file within that framework target using this syntax and substituting the appropriate names:

    1. #import <ProductName/ProductModuleName-Swift.h>

The Swift files in your framework target will be visible in Objective-C .m files containing this import statement. For information on using Swift from Objective-C code, see Using Swift from Objective-C.

Import into Swift

Import into Objective-C

Swift code

No import statement

#import <ProductName/ProductModuleName-Swift.h>

Objective-C code

No import statement; Objective-C umbrella header required

#import "Header.h"

Importing External Frameworks

You can import external frameworks that have a pure Objective-C codebase, a pure Swift codebase, or a mixed-language codebase. The process for importing an external framework is the same whether the framework is written in a single language or contains files from both languages. When you import an external framework, make sure the Defines Module build setting for the framework you’re importing is set to Yes.

You can import a framework into any Swift file within a different target using the following syntax:

  1. import FrameworkName

You can import a framework into any Objective-C .m file within a different target using the following syntax:

  1. @import FrameworkName;

Import into Swift

Import into Objective-C

Any language framework

import FrameworkName

@import FrameworkName;

Using Swift from Objective-C

Once you import your Swift code into Objective-C, use regular Objective-C syntax for working with Swift classes.

  1. MySwiftClass *swiftObject = [[MySwiftClass alloc] init];
  2. [swiftObject swiftMethod];

A Swift class or protocol must be marked with the @objc attribute to be accessible and usable in Objective-C. This attribute tells the compiler that this piece of Swift code can be accessed from Objective-C. If your Swift class is a descendant of an Objective-C class, the compiler automatically adds the @objc attribute for you. For more information, see Swift Type Compatibility.

You’ll have access to anything within a class or protocol that’s marked with the @objc attribute as long as it’s compatible with Objective-C. This excludes Swift-only features such as those listed here:

  • Generics

  • Tuples

  • Enumerations defined in Swift without Int raw value type

  • Structures defined in Swift

  • Top-level functions defined in Swift

  • Global variables defined in Swift

  • Typealiases defined in Swift

  • Swift-style variadics

  • Nested types

  • Curried functions

For example, a method that takes a generic type as an argument or returns a tuple will not be usable from Objective-C.

Referencing a Swift Class or Protocol in an Objective-C Header

To avoid cyclical references, don’t import Swift code into an Objective-C header (.h) file. Instead, you can forward declare a Swift class or protocol to reference it in an Objective-C interface.

  1. // MyObjcClass.h
  2. @class MySwiftClass;
  3. @protocol MySwiftProtocol;
  4. @interface MyObjcClass : NSObject
  5. - (MySwiftClass *)returnSwiftClassInstance;
  6. - (id <MySwiftProtocol>)returnInstanceAdoptingSwiftProtocol;
  7. // ...
  8. @end

Forward declarations of Swift classes and protocols can only be used as types for method and property declarations.

Adopting a Swift Protocol in an Objective-C Implementation

An Objective-C class can adopt a Swift protocol in its implementation (.m) file by importing the Xcode-generated header for Swift code and using a class extension.

  1. // MyObjcClass.m
  2. #import "ProductModuleName-Swift.h"
  3. @interface MyObjcClass () <MySwiftProtocol>
  4. // ...
  5. @end
  6. @implementation MyObjcClass
  7. // ...
  8. @end

Overriding Swift Names for Objective-C Interfaces

The Swift compiler automatically imports Objective-C code as conventional Swift code. It imports Objective-C class factory methods as Swift initializers, and Objective-C enumeration cases truncated names.

There may be edge cases in your code that are not automatically handled. If you need to change the name imported by Swift of an Objective-C method, enumeration case, or option set value, you can use the NS_SWIFT_NAME macro to customize how a declaration is imported.

Class Factory Methods

If the Swift compiler fails to identify a class factory method, you can use the NS_SWIFT_NAME macro, passing the Swift signature of the initializer to have it imported correctly. For example:

  1. + (instancetype)recordWithRPM:(NSUInteger)RPM NS_SWIFT_NAME(init(RPM:));

If the Swift compiler mistakenly identifies a method as a class factory method, you can use the NS_SWIFT_NAME macro, passing the Swift signature of the method to have it imported correctly. For example:

  1. + (id)recordWithQuality:(double)quality NS_SWIFT_NAME(record(quality:));

Enumerations

By default, Swift imports enumerations by truncating enumeration value name prefixes. To customize the name of an enumeration case, you can use the NS_SWIFT_NAME macro, passing the Swift enumeration case name. For example:

  1. typedef NS_ENUM(NSInteger, ABCRecordSide) {
  2. ABCRecordSideA,
  3. ABCRecordSideB NS_SWIFT_NAME("FlipSide"),
  4. };

Making Objective-C Interfaces Unavailable in Swift

Some Objective-C interfaces may not be suitable or necessary to be exposed as Swift interfaces. To prevent an Objective-C declaration from being imported by Swift, use the NS_SWIFT_UNAVAILABLE macro, passing a message directing API consumers to any alternatives that may exist.

For example, an Objective-C class providing a convenience initializer that takes variadic arguments for keys-value pairs may advise a Swift consumer to use a dictionary literal instead:

  1. + (instancetype)collectionWithKeysAndValues:(id)firstKey, ... NS_SWIFT_UNAVAILABLE("Use a dictionary literal instead");

Attempting to call the +collectionWithKeysAndValues: method from Swift code will result in a compiler error.

Naming Your Product Module

The name of the Xcode-generated header for Swift code, and the name of the Objective-C bridging header that Xcode creates for you, are generated from your product module name. By default, your product module name is the same as your product name. However, if your product name has any nonalphanumeric characters, such as a period (.), they are replaced with an underscore (_) in your product module name. If the name begins with a number, the first number is replaced with an underscore.

You can also provide a custom name for the product module name, and Xcode will use this when naming the bridging and generated headers. To do this, change the Product Module Name build setting.

Troubleshooting Tips and Reminders

  • Treat your Swift and Objective-C files as the same collection of code, and watch out for naming collisions.

  • If you’re working with frameworks, make sure the Defines Module build setting under Packaging is set to Yes.

  • If you’re working with the Objective-C bridging header, make sure the Objective-C Bridging Header build setting under Swift Compiler - Code Generation has a path to the header that’s relative to your project. The path must be directly to the file itself, not just to the directory that it’s in.

  • 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. For information on product module naming, see Naming Your Product Module.

  • To be accessible and usable in Objective-C, a Swift class must be a descendant of an Objective-C class or it must be marked @objc.

  • When you bring Swift code into Objective-C, remember that Objective-C won’t be able to translate certain features that are specific to Swift. For a list, see Using Swift from Objective-C.

  • If you use your own Objective-C types in your Swift code, make sure to import the Objective-C headers for those types before importing the Swift generated header into the Objective-C .m file you want to use your Swift code from.

  • Swift declarations marked with the private modifier do not appear in the generated header. Private declarations are not exposed to Objective-C unless they are explicitly marked with @IBAction, @IBOutlet, or @objc as well.

  • For app targets, declarations marked with the internal modifier appear in the generated header if the app target has an Objective-C bridging header.

  • For framework targets, only declarations with the public modifier appear in the generated header. You can still use Swift methods and properties that are marked with the internal modifier from within the Objective-C part of your framework, as long they are declared within a class that inherits from an Objective-C class. For more information on access-level modifiers, see Access Control in The Swift Programming Language.