Cách khắc phục là chính xác - không có gì về bộ chọn mà bạn có thể thay đổi để làm cho phương thức mà nó đề cập đến tiếp xúc với Objective-C.
Toàn bộ lý do cho cảnh báo này ở nơi đầu tiên là kết quả của SE-0160 . Trước Swift 4, internal
hoặc các thành viên tương thích Objective-C cao hơn củaNSObject
các lớp kế thừa đã được suy ra @objc
và do đó được tiếp xúc với Objective-C, do đó cho phép chúng được gọi bằng cách sử dụng các bộ chọn (vì thời gian chạy Obj-C là bắt buộc để tra cứu phương thức thực hiện cho một bộ chọn nhất định).
Tuy nhiên trong Swift 4, đây không còn là trường hợp nữa. Hiện tại, chỉ có các khai báo rất cụ thể được suy ra là @objc
ghi đè các @objc
phương thức, triển khai các @objc
yêu cầu giao thức và khai báo với các thuộc tính ngụ ý @objc
, chẳng hạn như@IBOutlet
.
Động lực đằng sau điều này, như chi tiết trong đề xuất được liên kết ở trên , trước hết là để ngăn chặn quá tải phương thức trongNSObject
kế thừa các lớp va chạm với nhau do có các bộ chọn giống hệt nhau. Thứ hai, nó giúp giảm kích thước nhị phân bằng cách không phải tạo thun cho các thành viên không cần phải tiếp xúc với Obj-C và thứ ba cải thiện tốc độ liên kết động.
Nếu bạn muốn giới thiệu một thành viên với Obj-C, bạn cần đánh dấu nó là @objc
, ví dụ:
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action: #selector(foo), for: .touchUpInside)
}
@objc func foo() {
// ...
}
}
(trình di chuyển sẽ tự động làm điều này cho bạn với các bộ chọn khi chạy với tùy chọn "thu nhỏ suy luận" được chọn)
Để giới thiệu một nhóm thành viên với Obj-C, bạn có thể sử dụng @objc extension
:
@objc extension ViewController {
// both exposed to Obj-C
func foo() {}
func bar() {}
}
Điều này sẽ phơi bày tất cả các thành viên được xác định trong Obj-C và đưa ra lỗi đối với bất kỳ thành viên nào không thể tiếp xúc với Obj-C (trừ khi được đánh dấu rõ ràng là @nonobjc
).
Nếu bạn có một lớp mà bạn cần tất cả các thành viên tương thích Obj-C được tiếp xúc với Obj-C, bạn có thể đánh dấu lớp đó là @objcMembers
:
@objcMembers
class ViewController: UIViewController {
// ...
}
Bây giờ, tất cả các thành viên có thể được suy luận @objc
sẽ được. Tuy nhiên, tôi không khuyên bạn nên làm điều này trừ khi bạn thực sự cần tất cả các thành viên tiếp xúc với Obj-C, với những nhược điểm đã đề cập ở trên về việc các thành viên tiếp xúc không cần thiết.
@objc
là cần thiết để đưa chúng ra Obj-C, và do đó sử dụng với bộ chọn.