Bản thân Swift không sử dụng các công cụ chọn - một số mẫu thiết kế trong Objective-C sử dụng các công cụ chọn hoạt động khác nhau trong Swift. (Ví dụ: sử dụng chuỗi tùy chọn trên các loại giao thức hoặc is
/ as
kiểm tra thay vì respondsToSelector:
và sử dụng các bao đóng bất cứ nơi nào bạn có thể thay vì performSelector:
để đảm bảo an toàn cho loại / bộ nhớ tốt hơn.)
Nhưng vẫn còn một số API dựa trên ObjC quan trọng sử dụng các bộ chọn, bao gồm bộ định thời và mẫu mục tiêu / hành động. Swift cung cấp Selector
loại để làm việc với những thứ này. (Swift tự động sử dụng điều này thay cho SEL
loại ObjC .)
Trong Swift 2.2 (Xcode 7.3) trở lên (bao gồm Swift 3 / Xcode 8 và Swift 4 / Xcode 9):
Bạn có thể xây dựng một Selector
kiểu hàm Swift bằng #selector
biểu thức.
let timer = Timer(timeInterval: 1, target: object,
selector: #selector(MyClass.test),
userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
with: button, with: otherButton)
Điều tuyệt vời về phương pháp này? Tham chiếu hàm được trình biên dịch Swift kiểm tra, do đó bạn chỉ có thể sử dụng #selector
biểu thức với các cặp lớp / phương thức thực sự tồn tại và đủ điều kiện để sử dụng làm bộ chọn (xem "Tính khả dụng của bộ chọn" bên dưới). Bạn cũng có thể làm cho tham chiếu chức năng của mình chỉ cụ thể như bạn cần, theo quy tắc Swift 2.2+ để đặt tên loại chức năng .
(Đây thực sự là một cải tiến so với @selector()
chỉ thị của ObjC , bởi vì -Wundeclared-selector
kiểm tra của trình biên dịch chỉ xác minh rằng bộ chọn có tên tồn tại. Tham chiếu hàm Swift mà bạn chuyển để #selector
kiểm tra sự tồn tại, tư cách thành viên trong một lớp và chữ ký loại.)
Có một vài cảnh báo bổ sung cho các tham chiếu hàm bạn chuyển đến #selector
biểu thức:
- Nhiều hàm có cùng tên cơ sở có thể được phân biệt bằng nhãn tham số của chúng bằng cú pháp đã nói ở trên để tham chiếu hàm (ví dụ
insertSubview(_:at:)
vs insertSubview(_:aboveSubview:)
). Nhưng nếu một hàm không có tham số, cách duy nhất để phân tán hàm đó là sử dụng as
ép kiểu với chữ ký loại của hàm (ví dụ foo as () -> ()
vs foo(_:)
).
- Có một cú pháp đặc biệt cho các cặp getter / setter thuộc tính trong Swift 3.0+. Ví dụ, cho một
var foo: Int
, bạn có thể sử dụng #selector(getter: MyClass.foo)
hoặc #selector(setter: MyClass.foo)
.
Ghi chú chung:
Các trường hợp #selector
không hoạt động và đặt tên: Đôi khi, bạn không có tham chiếu chức năng để tạo bộ chọn với (ví dụ: với các phương thức được đăng ký động trong thời gian chạy ObjC). Trong trường hợp đó, bạn có thể xây dựng một Selector
chuỗi từ: vd Selector("dynamicMethod:")
- mặc dù bạn mất kiểm tra tính hợp lệ của trình biên dịch. Khi bạn làm điều đó, bạn cần tuân theo các quy tắc đặt tên ObjC, bao gồm cả dấu hai chấm ( :
) cho mỗi tham số.
Tính khả dụng của bộ chọn: Phương thức được tham chiếu bởi bộ chọn phải được hiển thị với thời gian chạy ObjC. Trong Swift 4, mọi phương thức được hiển thị với ObjC phải được khai báo trước bằng @objc
thuộc tính. (Trong các phiên bản trước, bạn đã có thuộc tính đó miễn phí trong một số trường hợp, nhưng bây giờ bạn phải khai báo rõ ràng.)
Hãy nhớ rằng private
các biểu tượng không được tiếp xúc với thời gian chạy, quá - phương pháp của bạn cần phải có ít nhất internal
khả năng hiển thị.
Đường dẫn chính: Chúng có liên quan đến nhưng không hoàn toàn giống như bộ chọn. Cũng có một cú pháp đặc biệt cho những điều này trong Swift 3: vd chris.valueForKeyPath(#keyPath(Person.friends.firstName))
. Xem SE-0062 để biết chi tiết. Và thậm chí nhiều KeyPath
thứ khác trong Swift 4 , vì vậy hãy đảm bảo bạn đang sử dụng API dựa trên KeyPath phù hợp thay vì bộ chọn nếu thích hợp.
Bạn có thể đọc thêm về các công cụ chọn trong Tương tác với API Objective-C khi sử dụng Swift với Ca cao và Objective-C .
Lưu ý: Trước Swift 2.2, Selector
tuân thủ StringLiteralConvertible
, do đó bạn có thể tìm thấy mã cũ trong đó các chuỗi trần được chuyển đến các API có bộ chọn. Bạn sẽ muốn chạy "Chuyển đổi sang Cú pháp Swift hiện tại" trong Xcode để có được những người sử dụng #selector
.
selector: test()
sẽ gọitest
và chuyển giá trị trả về của nó choselector
đối số.