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.
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.
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”. For information on the product module name
You’ll need to edit this file to expose your Objective-C code to your Swift code.
To import Objective-C code into Swift from the same target
- In your Objective-C bridging header file, import every Objective-C header you want to expose to Swift. For example:Objective-C
#import "XYZCustomCell.h"
#import "XYZCustomView.h"
#import "XYZCustomViewController.h"
- 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 must be directly to the file itself, not the directory that it’s in.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.
Swift
let myCell = XYZCustomCell()
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 all of 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”. For information on the product module name
You don’t need to do anything special to create this file—you just
need to 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 prior to 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:Objective-C#import “ProductModuleName-Swift.h”
Any 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
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
- Under Build Settings, in Packaging, make sure the Defines Module setting for that framework target is set to Yes.
- In your umbrella header file, import every Objective-C header you want to expose to Swift. For example:Objective-C
#import <XYZ/XYZCustomCell.h>
#import <XYZ/XYZCustomView.h>
#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.
Swift
let myCell = XYZCustomCell()
myCell.subtitle = "A 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 that code from.
To import Swift code into Objective-C from the same framework
- Under Build Settings, in Packaging, make sure the Defines Module setting for that framework target is set to Yes.
- 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:Objective-C#import <ProductName/ProductModuleName-Swift.h>
Any 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
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:
Swift
import FrameworkName
You can import a framework into any Objective-C
.m
file within a different target using the following syntax:
Objective-C
@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.
Objective-C
MySwiftClass *swiftObject = [[MySwiftClass alloc] init];
[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
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
- 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.
To avoid cyclical references, don’t import Swift into an Objective-C
header file. Instead, you can forward declare a Swift class to use it in
an Objective-C header. However, note that you cannot subclass a Swift
class in Objective-C.
To reference a Swift class in an Objective-C header file
- Forward declare the Swift class you’re using:Objective-C
// MyObjcClass.h
@class MySwiftClass;
@interface MyObjcClass : NSObject
- (MySwiftClass *)returnSwiftObject;
/* ... */
@end
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
- 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.
- If you use your own Objective-C types in your Swift code, 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.
No comments:
Post a Comment