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
}
複製代碼