Objective-C 对象是基于运行时的,方法或属性使用动态派发 ,在运行调用时再决定实际调用的具体实现。而 Swift 为了追求性能,若是没有特殊须要的话,是不会在运行时再来决定这些的。也就是说,Swift 类型的成员或者方法在编译时就已经决定,而运行时便再也不须要通过一次查找,而能够直接使用。git
Objective-C 中全部类都继承自NSObject
,Swift 中的类若是要供 Objective-C 调用,必须也继承自NSObject
。github
@objc
修饰符的根本目的是用来暴露接口给 Objective-C 的运行时(类、协议、属性和方法等)express
添加@objc
修饰符并不意味着这个方法或者属性会采用 Objective-C 的方式变成动态派发,Swift 依然可能会将其优化为静态调用swift
@objc
修饰符的隐式添加:app
Swift 3 中继承自NSObject
的类,不须要手动添加@objc
,编译器会给全部的非private
的类和成员加上@objc
,private
接口想要暴露给 Objective-C 须要@objc
的修饰ide
button.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
@objc private func backButtonTapped() { }
func backButtonTapped() { }
复制代码
Swift 4 中继承自NSObject
的类的隐式@objc
自动添加,只会发生在如下四种状况:性能
@IBAction
或@IBOutlet
关键字的修饰@NSManaged
关键字的修饰使用@objc
能够修改 Swift 接口暴露到 Objective-C 后的名字优化
@objc(Squirrel)
class Белка: NSObject {
@objc(color)
var цвет: Цвет = .Красный
@objc(hideNuts:inTree:)
func прячьОрехи(количество: Int, вДереве дерево: Дерево) { }
}
复制代码
Swift4 后继承自NSObject
的类再也不隐式添加@objc
关键字,但在某些状况下很是依赖 Objective-C 的运行时(如 XCTest),因此在 Swift4 中提供了@objcMembers
关键字,对类和子类、扩展和子类扩展从新启用@objc
推断。ui
@objcMembers
class MyClass : NSObject {
func foo() { } // implicitly @objc
func bar() -> (Int, Int) // not @objc, because tuple returns
// aren't representable in Objective-C
}
extension MyClass {
func baz() { } // implicitly @objc
}
class MySubClass : MyClass {
func wibble() { } // implicitly @objc
}
extension MySubClass {
func wobble() { } // implicitly @objc
}
复制代码
使用@objc
和@nonobjc
能够指定开启或关闭某一extension
中的全部方法的@objc
推断。this
class SwiftClass { }
@objc extension SwiftClass {
func foo() { } // implicitly @objc
func bar() -> (Int, Int) // error: tuple type (Int, Int) not
// expressible in @objc. add @nonobjc or move this method to fix the issue
}
@objcMembers
class MyClass : NSObject {
func wibble() { } // implicitly @objc
}
@nonobjc extension MyClass {
func wobble() { } // not @objc, despite @objcMembers
}
复制代码
当前 Swift 的动态性依赖于 Objective-C,Swift3 中dynamic
就隐式包含了@objc
的意思,但考虑到之后版本的 Swift 语言和运行时将会自支持dynamic
而再也不依赖于 Objective-C,因此在 Swift4 中将dynamic
和@objc
含义进行了抽离。
class MyClass {
dynamic func foo() { } // error: 'dynamic' method must be '@objc'
@objc dynamic func bar() { } // okay
}
复制代码