Сам Swift не использует селекторы - несколько шаблонов проектирования, которые в Objective-C используют селекторы, работают по-разному в Swift. (Например, используйте дополнительные цепочки для типов протоколов или is
/ as
tests вместо 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+ есть специальный синтаксис для пар методов получения / установки свойств. Например, учитывая
var foo: Int
, вы можете использовать #selector(getter: MyClass.foo)
или #selector(setter: MyClass.foo)
.
Главные примечания:
Случаи, когда #selector
не работает, и именование: Иногда у вас нет ссылки на функцию, с которой можно сделать селектор (например, с методами, динамически зарегистрированными во время выполнения ObjC). В этом случае вы можете создать a Selector
из строки: например, Selector("dynamicMethod:")
- хотя вы потеряете проверку корректности компилятора. Когда вы делаете это, вы должны следовать правилам именования ObjC, включая colons ( :
) для каждого параметра.
Доступность селектора: метод, на который ссылается селектор, должен быть открыт для среды выполнения 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» .
Примечание. До Selector
версии Swift 2.2 это соответствовало требованиям StringLiteralConvertible
, поэтому вы можете найти старый код, в котором голые строки передаются в API, которые принимают селекторы. Вы захотите запустить «Преобразовать в текущий синтаксис Swift» в XCode, чтобы получить их использующие #selector
.
selector: test()
будет вызыватьtest
и передавать это возвращаемое значение вselector
аргумент.