Disabling Swift 3 @objc inference in Xcode 9

Today I installed Xcode 9 and converted my projects to Swift 4.0. Surprisingly, very few changes were necessary to make my code compatible with the new Swift. However, one warning showed up after the build:

The use of Swift 3 @objc inference in Swift 4 mode is deprecated. Please address deprecated @objc inference warnings, test your code with “Use of deprecated Swift 3 @objc inference” logging enabled, and disable Swift 3 @objc inference.

Here is how I got rid of that warning:

  1. Click on your project in the Project Navigator.
  2. Select your target.
  3. Click Build Settings.
  4. In the search bar type "inference" to quickly find the settings.
  5. Finally, change the "Swift 3 @objc Inference" settings to "Default" and rebuild the project.

Disabling Swift 3 @objc inrefence in Xcode 9

What does "Swift 3 @objc Inference" setting do?

Before Swift 4, the compiler made some Swift declarations automatically available to Objective-C. For example, if one subclassed from NSObject, the compiler created Objective-C entry points for all methods in such classes. The mechanism is called @objc inference.

In Swift 4, such automatic @objc inference is deprecated because it is costly to generate all those Objective-C entry points. When "Swift 3 @objc Inference" setting is set to "On", it allows the old code to work. However, it will show deprecation warnings that need to be addressed. It is recommended to "fix" these warnings and switch the setting to "Default", which is the default for new Swift projects.

Example 1: before Swift 4

This code worked before Swift 4, since method foo was automatically exposed to Objective-C:

class MyClass: NSObject {
  func foo() {}

  func test() {
    var cl: AnyObject
    cl = MyClass()
    cl.foo?() // No problem before Swift 4
  }
}

Example 2: since Swift 4

Let's try running the same code in Swift 4:

class MyClass: NSObject {
  func foo() {}

  func test() {
    var cl: AnyObject
    cl = MyClass()
    cl.foo?() // Error: Value of type 'AnyObject' has no member 'foo'
  }
}

Now the compiler shows an error, since foo method is no longer available from Objective-C. For convenience, the Swift 4 code migration sets "Swift 3 @objc Inference" setting to "On", which makes our code compile with the following warning:

Reference to instance method 'foo()' of 'MyClass' depends on '@objc' attribute inference deprecated in Swift 4.

Make class members available to Objective-C

If we want declarations to be accessible from Objective-C we can mark individual members with the @objc annotation:

class MyClass : NSObject {
  @objc func foo() { } // This method is available to Objective-C
  func bar() { } // But not this method
}

Alternatively, if we want all members of our class to be exposed to Objective-C, we can mark the class with @objcMembers annotation:

@objcMembers // All class members will be exposed to Objective-C
class MyClass : NSObject {
  func foo() { }
  func bar() { }
}

References







Wooooow!