背景
Objective-C 物件是基於執行時的,方法或屬性使用動態派發 ,在執行呼叫時再決定實際呼叫的具體實現。而 Swift 為了追求效能,如果沒有特殊需要的話,是不會在執行時再來決定這些的。也就是說,Swift 型別的成員或者方法在編譯時就已經決定,而執行時便不再需要經過一次查詢,而可以直接使用。
Objective-C 中所有類都繼承自NSObject
,Swift 中的類如果要供 Objective-C 呼叫,必須也繼承自NSObject
。
@objc
-
@objc
修飾符的根本目的是用來暴露介面給 Objective-C 的執行時(類、協議、屬性和方法等) -
新增
@objc
修飾符並不意味著這個方法或者屬性會採用 Objective-C 的方式變成動態派發,Swift 依然可能會將其優化為靜態呼叫 -
@objc
修飾符的隱式新增:-
Swift 3 中繼承自
NSObject
的類,不需要手動新增@objc
,編譯器會給所有的非private
的類和成員加上@objc
,private
介面想要暴露給 Objective-C 需要@objc
的修飾button.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside) @objc private func backButtonTapped() { } func backButtonTapped() { } 複製程式碼
-
Swift 4 中繼承自
NSObject
的類的隱式@objc
自動新增,只會發生在以下四種情況:- 重寫了父類的 Objective-C 方法
- 實現了一個 Objective-C 的協議
@IBAction
或@IBOutlet
關鍵字的修飾@NSManaged
關鍵字的修飾
-
-
使用
@objc
可以修改 Swift 介面暴露到 Objective-C 後的名字@objc(Squirrel) class Белка: NSObject { @objc(color) var цвет: Цвет = .Красный @objc(hideNuts:inTree:) func прячьОрехи(количество: Int, вДереве дерево: Дерево) { } } 複製程式碼
@objcMembers
Swift4 後繼承自NSObject
的類不再隱式新增@objc
關鍵字,但在某些情況下非常依賴 Objective-C 的執行時(如 XCTest),所以在 Swift4 中提供了@objcMembers
關鍵字,對類和子類、擴充套件和子類擴充套件重新啟用@objc
推斷。
@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
推斷。
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
}
複製程式碼
dynamic
當前 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
}
複製程式碼