Although the purpose of Swift is to throw the burden of Objective-C, no one could ignore the position of Objective-C in Cocoa. Especially it is used for almost 20 years as the tool for the Apple system, countless third party libraries are written in Objective-C. In early time of Swift, the compatibility with Objective-C is a must feature for anybody.

Apple allows us to use Swift and Objective-C in the same project to develop an app. But Objective-C files and Swift ones are in different world by default. To make them connect with each other, we are required to add a bridge between them.

First thing to do would be to add a file with the name of {product-module-name}-Bridging-Header.h into the project. After adding it, we could append Objective-C header files we need to use in this file. Swift modules can understand this file and generate corresponding API in a Swift syntax, then you can use these APIs in your own code. To make this easier, Xcode even implement a guide for it. When you first add an Objective-C file to a Swift project, the IDE would prompt to ask if you want to create this file automatically. I bet you may want to select YES every time.

Conversely, to use Swift types and methods in Objective-C is not so direct. If you want to use a third party prebuilt framework written in Objective-C, you have to import the framework first. Compiler will not take care of the framework binary is developed in Swift or Objective-C, you just use @import to make a module available:

@import MySwiftKit;

After that, you can use the framework in your Objective-C source.

If you can get the source of the Swift files, you can import an automatically generated header file of Swift module to use it. The name of that file is {product-module-name}-Swift.h. For example, you have an app with target name MyApp, and you want to use some Swift types and method in the target, in your Objective-C file, write this:

#import "MyApp-Swift.h"

This is only the beginning of the whole story. Swift is different from Objective-C under the hood. Objective-C object (NSObject) in Cocoa is based upon the runtime. It follows Key-Value-Coding and dynamic dispatch. While in Swift, high performance and safer implementation are in high priority. When not necessary, these things will not be done at runtime. In other words, members of a type, including the properties and methods are determined in compiling time. There is no need to search and use in runtime. We can use them directly, which boosts the operation.

Obviously, the problem is, when we use Objective-C runtime feature to call pure Swift method, it would fail due to there might be no runtime information. It is not so hard to resolve it, in Swift files, we can expose the types, properties or methods to Objective-C by adding @objc before them. This is only needed when you are in a pure Swift type. If your Swift class is inherited from NSObject, Swift will add @objc in all non-private classes and members implicitly. That means, if you are working on an NSObject subclass in Swift, just import header file in Objective-C and you are ready to go. Otherwise, you need to add @objc manually.

Another use case of @objc is renaming the name of a method or variable. Most of time, auto mapped names are reasonable and easy to use (for example thing like init(name: String) in Swift will be converted into -initWithName:(NSString *)name in Objective-C). However, there is the situation we want to use a different name in Objective-C other than in Swift. For example, you have to use a framework written in Chinese (which is possible in Swift because it supports UTF8!)

class 我的类 {
    func 打招呼(名字: String) {
        print("哈喽,\(名字)")
    }
}

我的类().打招呼("Tom")

Although I like Chinese very much, unfortunately, we cannot use Chinese to call method in Objective-C. So we must use @objc to convert it to an ASCII version to access in Objective-C:

@objc(MyClass)
class 我的类 {
    @objc(greeting:)
    func 打招呼(名字: String) {
        print("哈喽,\(名字)")
    }
}

// In Objective-C
[[MyClass new] greeting:@"Tom"];

As mentioned above and in the Selector section, even in NSObject subclass, Swift will not mark @objc in a private method, due to it should only be seen in that file and should not have interactive with Objective-C by default. If we really want to use them from a runtime feature, we should add @objc ourselves.

Adding @objc does not mean this method or property will follow dynamic dispatch way. There is likewise a possibility for the compiler to optimize it to a static calling. If you need the very same runtime feature in Objective-C for your Swift code, you could use dynamic instead. In regular development of a simple app, it should not be used. But if you have code swizzling method in runtime or some other "black magic", you will need it. We will mention an example of dynamic in the KVO section later.