How do I call Objective-C code from Swift?
objective-c, swift
Solution
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 <Foundation/Foundation.h` to an older Objective-C File.)
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:
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
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 <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
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:
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.
Problem
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?