Сам Swift не використовує селектори - кілька моделей дизайну, які в Objective-C використовують селектори, по-різному працюють у Swift. (Наприклад, замість них використовуйте необов'язкові ланцюжки на типи протоколів або is/ asтести respondsToSelector:та використовуйте закриття, де можна, замість performSelector:кращої безпеки типу / пам’яті.)
Але є ще ряд важливих API на основі ObjC, які використовують селектори, включаючи таймери та шаблон цілі / дії. Swift надає Selectorтип роботи з ними. (Swift автоматично використовує це замість типу ObjC SEL.)
У Swift 2.2 (Xcode 7.3) та пізніших версіях (включаючи Swift 3 / Xcode 8 та Swift 4 / Xcode 9):
Ви можете побудувати а Selectorз типу функції Swift, використовуючи #selectorвираз.
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)
Чудова річ у цьому підході? Посилання на функцію перевіряється компілятором Swift, тож ви можете використовувати #selectorвираз тільки з парами класів / методів, які існують і є допустимими для використання в якості селекторів (див. "Доступність селектора" нижче). Ви також можете зробити посилання на свою функцію лише настільки конкретною, скільки вам потрібно, відповідно до правил Swift 2.2+ для іменування типу функції .
(Це насправді вдосконалення щодо @selector()директиви ObjC , оскільки -Wundeclared-selectorперевірка компілятора підтверджує лише наявність названого селектора. Посилання функції Swift, яке ви передаєте, #selectorперевіряє наявність, членство в класі та підпис типу.)
Є кілька додаткових застережень для посилань на функцію, які ви передаєте #selectorвиразу:
- Кілька функцій з тим самим базовим іменем можна диференціювати за їх мітками параметрів, використовуючи вищезазначений синтаксис для посилань на функції (наприклад,
insertSubview(_:at:)vs insertSubview(_:aboveSubview:)). Але якщо функція не має параметрів, єдиний спосіб роз'єднати її - використовувати asкоманду з підписом типу функції (наприклад, foo as () -> ()vs foo(_:)).
- У Swift 3.0+ є спеціальний синтаксис для пар власників / сеттер. Наприклад, давши a
var foo: Int, ви можете використовувати #selector(getter: MyClass.foo)або #selector(setter: MyClass.foo).
Загальні примітки:
Випадки, коли #selectorне працює, і іменування: Іноді у вас немає посилання на функцію, щоб зробити селектор (наприклад, методами, динамічно зареєстрованими в ObjC час виконання). У цьому випадку ви можете побудувати a Selectorз рядка: напрSelector("dynamicMethod:") - хоча ви втратите перевірку дійсності компілятора. Коли ви робите це, вам потрібно дотримуватися правил іменування ObjC, включаючи кольори ( :) для кожного параметра.
Доступність селектора: Метод, на який посилається селектор, повинен піддаватися виконанню ObjC. У Swift 4 кожен метод, що піддається впливу ObjC, повинен мати своє декларування попереднім@objc атрибутом. (У попередніх версіях ви отримали цей атрибут безкоштовно в деяких випадках, але тепер вам це потрібно чітко заявити.)
Пам’ятайте, що privateсимволи також не піддаються виконанню - ваш метод повинен мати принаймніinternal видимість.
Основні шляхи: вони пов'язані, але не зовсім такі ж, як селектори. Для Swift 3 теж є спеціальний синтаксис: напр chris.valueForKeyPath(#keyPath(Person.friends.firstName)). Детальніше див. У SE-0062 . І ще більше KeyPathматеріалів у Swift 4 , тому переконайтесь, що ви використовуєте правильний API на основі KeyPath замість селекторів, якщо це доречно.
Докладніше про селектори можна прочитати у розділі Взаємодія з API-кодами Objective-C у користуванні Swift з какао та Objective-C .
Примітка: Перед Swift 2.2, Selectorвідповідно до StringLiteralConvertible, таким чином, ви можете знайти старий код, де голі рядки передаються API, що приймають селектори. Вам потрібно запустити "Перетворити на поточний синтаксис Swift" у Xcode, щоб отримати тих, хто використовує #selector.
selector: test()зателефонував биtestі передав би це значення поверненняselectorаргументу.