Я пытаюсь создать NSTimer
ин , Swift
но у меня возникают некоторые проблемы.
NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)
test()
это функция в том же классе.
Я получаю ошибку в редакторе:
Не удалось найти перегрузку для 'init', который принимает предоставленные аргументы
Когда я изменяю selector: test()
к selector: nil
по ошибке исчезает.
Я пробовал:
selector: test()
selector: test
selector: Selector(test())
Но ничего не работает, и я не могу найти решение в ссылках.
selector: test()
будет вызыватьtest
и передавать это возвращаемое значение вselector
аргумент.Ответы:
Сам Swift не использует селекторы - несколько шаблонов проектирования, которые в Objective-C используют селекторы, работают по-разному в Swift. (Например, используйте дополнительные цепочки для типов протоколов или
is
/as
tests вместоrespondsToSelector:
, и используйте замыкания везде, где вы можете вместоperformSelector:
лучшей безопасности типов / памяти.)Но есть еще ряд важных API на основе ObjC, которые используют селекторы, включая таймеры и шаблон назначения / действия. Swift предоставляет
Selector
тип для работы с ними. (Swift автоматически использует это вместо типа ObjCSEL
.)В Swift 2.2 (Xcode 7.3) и более поздних версиях (включая Swift 3 / Xcode 8 и Swift 4 / Xcode 9):
Вы можете создать
Selector
функцию из типа Swift, используя#selector
выражение.Что хорошего в этом подходе? Ссылка на функцию проверяется компилятором Swift, поэтому вы можете использовать
#selector
выражение только с теми парами класс / метод, которые действительно существуют и могут использоваться в качестве селекторов (см. «Доступность селектора» ниже). Вы также можете свободно ссылаться на свои функции только в соответствии с вашими требованиями, согласно правилам Swift 2.2+ для именования типов функций .(На самом деле это улучшение по сравнению с
@selector()
директивой ObjC , поскольку-Wundeclared-selector
проверка компилятором проверяет только существование именованного селектора. Ссылка на функцию Swift, которую вы передаете для#selector
проверки существования, членства в классе и подписи типа.)Есть несколько дополнительных предостережений для ссылок на функции, которые вы передаете
#selector
выражению:insertSubview(_:at:)
vsinsertSubview(_:aboveSubview:)
). Но если функция не имеет параметров, единственный способ устранить ее неоднозначность - это использоватьas
приведение с сигнатурой типа функции (например,foo as () -> ()
vsfoo(_:)
).var foo: Int
, вы можете использовать#selector(getter: MyClass.foo)
или#selector(setter: MyClass.foo)
.Главные примечания:
Случаи, когда
#selector
не работает, и именование: Иногда у вас нет ссылки на функцию, с которой можно сделать селектор (например, с методами, динамически зарегистрированными во время выполнения ObjC). В этом случае вы можете создать aSelector
из строки: например,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
.источник
size:andShape:
если первый аргумент назван, вам может понадобитьсяWith
, то естьinitWithData:
дляfunc init(Data data: NSData)
Вот краткий пример использования
Selector
класса в Swift:Обратите внимание, что если метод, переданный в виде строки, не работает, он потерпит неудачу во время выполнения, а не во время компиляции и приведет к сбою приложения. Быть осторожен
источник
@selector
удобно, но не так строго, как вы думаете. «Необъявленный селектор» - это просто предупреждение от компилятора, потому что новые селекторы всегда могут быть введены во время выполнения. Впрочем, ссылки на проверяемые / рефакторируемые селекторы в Swift могут быть полезны .Кроме того, если ваш (Swift) класс не происходит от класса Objective-C, то у вас должно быть двоеточие в конце строки имени целевого метода, и вы должны использовать свойство @objc с вашим целевым методом, например
в противном случае вы получите ошибку «Нераспознанный селектор» во время выполнения.
источник
Selector
ключевое слово не обязательно. Так что в этом случае подпись должна быть@objc func method(timer: NSTimer) {/*code*/}
@objc
работал на меня. Мне не нужно было включатьtimer: NSTimer
в мой метод подпись для его вызова.Обновление Swift 2.2+ и Swift 3
Используйте новое
#selector
выражение, которое избавляет от необходимости использовать строковые литералы, делая использование менее подверженным ошибкам. Для справки:становится
Смотрите также: Предложение Swift Evolution
Примечание (Swift 4.0):
При использовании
#selector
вам нужно пометить функцию как@objc
Пример:
@objc func something(_ sender: UIButton)
источник
Swift 4.0
Вы создаете селектор, как показано ниже.
1. добавить событие к кнопке, как:
и функция будет как ниже:
источник
@objc
перед тем,func
что требуется в Swift 4.Для будущих читателей я обнаружил, что у меня возникла проблема, и я получил
unrecognised selector sent to instance
ошибку, вызванную пометкой целиfunc
как частной.func
ДОЛЖНО быть общедоступным , чтобы назвать объект со ссылкой на селектор.источник
objc
его до объявления. Пример:@objc private func foo() { ...
тогда вы можете использовать"foo"
в качестве селектора столько, сколько вам нравитсяinternal
, таким образом, не указывая какой-либо модификатор доступа. Я часто использую этот шаблон://MARK: - Selector Methods\n extension MyController {\n func buttonPressed(_ button: UIButton) {
Просто в случае, если у кого-то еще есть та же проблема, что и у меня с NSTimer, где ни один из других ответов не устранил проблему, очень важно отметить, что, если вы используете класс, который не наследует от NSObject ни напрямую, ни глубоко в иерархии ( например, созданные вручную файлы swift), ни один из других ответов не будет работать, даже если указано следующее:
Не изменяя ничего, кроме простого наследования класса от NSObject, я перестал получать сообщение об ошибке «Нераспознанный селектор» и заставил мою логику работать так, как ожидалось.
источник
Если вы хотите передать параметр в функцию из NSTimer, вот ваше решение:
Включите двоеточие в текст селектора (tester :), а ваши параметры перейдите в userInfo.
Ваша функция должна принимать NSTimer в качестве параметра. Затем просто извлеките userInfo, чтобы получить переданный параметр.
источник
scheduledTimerWith...
автоматически добавляет его в текущий цикл запуска - так что здесь вообще нет странного поведения;)Селекторы являются внутренним представлением имени метода в Objective-C. В Objective-C "@selector (methodName)" будет преобразовывать метод исходного кода в тип данных SEL. Поскольку вы не можете использовать синтаксис @selector в Swift (здесь есть рикстер), вы должны вручную указать имя метода как объект String напрямую или передать объект String типу Selector. Вот пример:
или
источник
Swift 4.1
с образцом жеста касания
См. Документ Apple для более подробной информации о: выражении селектора
источник
источник
// Обновить метод управления
источник
Поскольку Swift 3.0 опубликован, даже немного сложнее объявить подходящим targetAction
источник
Когда используешь
performSelector()
/addtarget()/NStimer.scheduledTimerWithInterval()
Методы вашего метода (соответствующие селектору) должны быть помечены какДля Swift 2.2 вам нужно написать «#selector ()» вместо строки и имени селектора, чтобы больше не было возможности орфографической ошибки и сбоя из-за этого. Ниже приведен пример
источник
Вы создаете селектор, как показано ниже.
1.
2.
Обратите внимание, что синтаксис @selector пропал и заменен простой строкой с именем вызываемого метода. Есть одна область, в которой мы все можем согласиться с многословием, возникшим на пути. Конечно, если мы объявили, что существует целевой метод с именем flatButtonPressed: лучше написать один:
установить таймер:
Чтобы быть полным, вот flatButtonPressed
источник
Я нашел, что многие из этих ответов были полезны, но не было ясно, как сделать это с чем-то, что не было кнопкой. Я быстро добавлял распознаватель жестов в UILabel и старался изо всех сил, поэтому вот что я нашел, сработав для меня после прочтения всего выше:
Где «Селектор» был объявлен как:
Обратите внимание, что он общедоступен, и что я не использую синтаксис Selector (), но это также возможно.
источник
Использование #selector проверит ваш код во время компиляции, чтобы убедиться, что метод, который вы хотите вызвать, действительно существует. Еще лучше, если метод не существует, вы получите ошибку компиляции: Xcode откажется создавать ваше приложение, тем самым изгнав забвение другого возможного источника ошибок.
источник
Может быть полезно отметить, где вы устанавливаете элемент управления, запускающий действие.
Например, я обнаружил, что при настройке UIBarButtonItem мне нужно было создать кнопку внутри viewDidLoad, иначе я бы получил нераспознанное исключение селектора.
источник
selector
это слово изObjective-C
мира, и вы можете использовать его,Swift
чтобы иметь возможность позвонитьObjective-C
изSwift
него позволяет выполнять некоторый код во время выполненияПеред
Swift 2.2
синтаксисом это:Поскольку имя функции передается
Selector
какString
параметр ("foo"), невозможно проверить имя во время компиляции . В результате вы можете получить ошибку во время выполнения:После
Swift 2.2+
синтаксиса это:Автозаполнение XCode поможет вам вызвать правильный метод
источник
Изменить как простое именование строк в методе, вызывающем синтаксис селектора
После этого введите func test ().
источник
Для Swift 3
// Пример кода для создания таймера
источник
Селектор в Swift 4:
источник
Для быстрой 3
Объявление функции в том же классе:
источник
self
в селекторе. Этого должно быть достаточно:let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(test), userInfo: nil, repeats: true)