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?
Call the Objective-C library from Swift code by simply adding a bridging header to your project, and importing the appropriate headers.
You can work with types declared in Swift from within the Objective-C code in your project by importing an Xcode-generated header file. This file is an Objective-C header that declares the Swift interfaces in your target, and you can think of it as an umbrella header for your Swift code.
You can use all Objective-C code in Swift, and you can even use Swift in Objective-C. It's very crucial to be able to use the Cocoa framework. All of the code that is written in Objective-C is available for use in Swift, both Apple frameworks and third-party libraries as well.
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 <Foundation/Foundation.h
to an older Objective-C File.)
Add a .m
file to your class, and name it CustomObject.m
.
When adding your .m
file, you'll likely be hit with a prompt that looks like this:
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:
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
Add another .h
file and name it CustomObject.h
.
In CustomObject.h
#import <Foundation/Foundation.h> @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
In YourProject-Bridging-Header.h
:
#import "CustomObject.h"
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.
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)" } }
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.
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);
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.
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.
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.
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
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With