@selector () в Swift?

Я пытаюсь создать NSTimer в Swift но у меня проблемы.

 NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true) 

test() – это функция в том же classе.


Я получаю сообщение об ошибке в редакторе:

Не удалось найти перегрузку для «init», которая принимает поставленные аргументы

Когда я меняю selector: test() на selector: nil ошибка исчезает.

Я пробовал:

  • selector: test()
  • selector: test
  • selector: Selector(test())

Но ничего не работает, и я не могу найти решение в ссылках.

Сам Swift не использует селекторы – несколько шаблонов проектирования, которые в Objective-C используют селектора, работают по-разному в Swift. (Например, используйте необязательную привязку к типам протоколов или is / или вместо тестов performSelector: и используйте блокировки везде, где вы можете, а не для выполнения performSelector: для повышения безопасности по типу / памяти.)

Но по-прежнему существует ряд важных API на основе ObjC, в которых используются селекторы, включая таймеры и шаблон цели / действия. Swift предоставляет тип Selector для работы с ними. (Swift автоматически использует это вместо SEL типа ObjC).

В 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 только с парами classа / метода, которые фактически существуют и могут использоваться в качестве селекторов (см. Ниже «Доступность селектора»). Вы также можете сделать ссылку на свою функцию только такой конкретной, какой вам требуется, в соответствии с правилами Swift 2.2+ для именования типов функций .

(Это на самом деле является улучшением по сравнению с директивой @selector() , поскольку проверка компилятора -Wundeclared-selector проверяет только то, что именованный селектор существует. Ссылка на функцию Swift, которую вы передаете на #selector проверяет существование, членство в classе и подпись типа .)

Есть пара дополнительных оговорок для ссылок на функции, которые вы передаете в выражение #selector :

  • Множественные функции с одним и тем же базовым именем могут быть дифференцированы по их меткам параметров с использованием вышеупомянутого синтаксиса для ссылок на функции (например, insertSubview(_:at:) vs insertSubview(_:aboveSubview:) ). Но если функция не имеет параметров, единственный способ ее устранить – использовать в as подписи подпись типа функции (например, foo as () -> () vs foo(_:) ).
  • В Swift 3.0+ есть специальный синтаксис для пар getter / setter. Например, с учетом var foo: Int вы можете использовать #selector(getter: MyClass.foo) или #selector(setter: MyClass.foo) .

Общие замечания:

Случаи, в которых #selector не работает, и именование: иногда у вас нет ссылки на функцию, чтобы сделать селектор с (например, с помощью методов, динамически зарегистрированных в среде выполнения ObjC). В этом случае вы можете построить 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 с Cocoa и Objective-C .

Примечание. Перед Swift 2.2 Selector соответствовал StringLiteralConvertible , поэтому вы можете найти старый код, где голые строки передаются API, которые принимают селекторы. Вы захотите запустить «Преобразовать в текущий Swift Syntax» в Xcode, чтобы получить те, которые используют #selector .

Вот краткий пример того, как использовать class Selector в Swift:

 override func viewDidLoad() { super.viewDidLoad() var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method")) self.navigationItem.rightBarButtonItem = rightButton } func method() { // Something cool here } 

Обратите внимание, что если метод, переданный как строка, не работает, он будет работать не во время выполнения, а не во время компиляции и сбой вашего приложения. Быть осторожен

Кроме того, если ваш (Swift) class не спускается с classа Objective-C, тогда у вас должен быть двоеточие в конце строки имени целевого метода, и вы должны использовать свойство @objc с вашим целевым методом, например

 var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method")) @objc func method() { // Something cool here } 

в противном случае во время выполнения вы получите сообщение «Unrecognized Selector».

Для будущих читателей я обнаружил, что я столкнулся с проблемой и получал unrecognised selector sent to instance ошибку, которая была вызвана тем, что целевая func закрытой.

Функция должна быть общедоступной для вызова объектом со ссылкой на селектор.

Обновление Swift 2.2+ и Swift 3

Используйте новое выражение #selector , которое устраняет необходимость использования строковых литералов, что делает использование менее подверженным ошибкам. Для справки:

 Selector("keyboardDidHide:") 

становится

 #selector(keyboardDidHide(_:)) 

См. Также: Предложение Swift Evolution

Примечание (Swift 4.0):

Если вы используете #selector вам нужно будет пометить функцию как @objc

Пример:

@objc func something(_ sender: UIButton)

На всякий случай, если у кого-то еще была такая же проблема, с которой я столкнулся с NSTimer, где ни один из других ответов не устранил проблему, действительно важно отметить, что если вы используете class, который не наследует NSObject напрямую или глубоко в иерархии ( например, созданные вручную быстрые файлы), ни один из других ответов не будет работать, даже если он указан следующим образом:

 let timer = NSTimer(timeInterval: 1, target: self, selector: "test", userInfo: nil, repeats: false) func test () {} 

Без изменения чего-либо другого, кроме как просто наследования classа из NSObject, я перестала получать ошибку «Unrecognized selector» и получила свою логическую работу, как ожидалось.

Swift 4.0

вы создаете селектор, как показано ниже.

1.add на кнопку, например:

 button.addTarget(self, action: #selector(clickedButton(sender:)), for: UIControlEvents.touchUpInside) 

и функция будет выглядеть следующим образом:

 @objc func clickedButton(sender: AnyObject) { } 

Если вы хотите передать параметр функции из NSTimer, то вот ваше решение:

 var somethingToPass = "It worked" let timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "tester:", userInfo: somethingToPass, repeats: false) func tester(timer: NSTimer) { let theStringToPrint = timer.userInfo as String println(theStringToPrint) } 

Включите двоеточие в текст селектора (тестер :), и ваши параметры заходят в userInfo.

В качестве параметра ваша функция должна принимать NSTimer. Затем просто извлеките userInfo, чтобы получить переданный параметр.

Селекторы представляют собой внутреннее представление имени метода в Objective-C. В Objective-C «@selector (methodName)» преобразует метод исходного кода в тип данных SEL. Поскольку вы не можете использовать синтаксис @selector в Swift (здесь находится rickster), вам нужно вручную указать имя метода как объект String напрямую или передать объект String в тип Selector. Вот пример:

 var rightBarButton = UIBarButtonItem( title: "Logout", style: UIBarButtonItemStyle.Plain, target: self, action:"logout" ) из var rightBarButton = UIBarButtonItem( title: "Logout", style: UIBarButtonItemStyle.Plain, target: self, action:"logout" ) 

или

 var rightBarButton = UIBarButtonItem( title: "Logout", style: UIBarButtonItemStyle.Plain, target: self, action:Selector("logout") ) 
 // for swift 2.2 // version 1 buttton.addTarget(self, action: #selector(ViewController.tappedButton), forControlEvents: .TouchUpInside) buttton.addTarget(self, action: #selector(ViewController.tappedButton2(_:)), forControlEvents: .TouchUpInside) // version 2 buttton.addTarget(self, action: #selector(self.tappedButton), forControlEvents: .TouchUpInside) buttton.addTarget(self, action: #selector(self.tappedButton2(_:)), forControlEvents: .TouchUpInside) // version 3 buttton.addTarget(self, action: #selector(tappedButton), forControlEvents: .TouchUpInside) buttton.addTarget(self, action: #selector(tappedButton2(_:)), forControlEvents: .TouchUpInside) func tappedButton() { print("tapped") } func tappedButton2(sender: UIButton) { print("tapped 2") } // swift 3.x button.addTarget(self, action: #selector(tappedButton(_:)), for: .touchUpInside) func tappedButton(_ sender: UIButton) { // tapped } button.addTarget(self, action: #selector(tappedButton(_:_:)), for: .touchUpInside) func tappedButton(_ sender: UIButton, _ event: UIEvent) { // tapped } 

Swift 4.1
С образцом жесты крана

 let gestureRecognizer = UITapGestureRecognizer() self.view.addGestureRecognizer(gestureRecognizer) gestureRecognizer.addTarget(self, action: #selector(self.dismiss(completion:))) // Use destination 'Class Name' directly, if you selector (function) is not in same class. //gestureRecognizer.addTarget(self, action: #selector(DestinationClass.dismiss(completion:))) @objc func dismiss(completion: (() -> Void)?) { self.dismiss(animated: true, completion: completion) } 

Дополнительную информацию о выражении Selector Expression см. В документе Apple.

 Create Refresh control using Selector method. var refreshCntrl : UIRefreshControl! refreshCntrl = UIRefreshControl() refreshCntrl.tintColor = UIColor.whiteColor() refreshCntrl.attributedTitle = NSAttributedString(string: "Please Wait...") refreshCntrl.addTarget(self, action:"refreshControlValueChanged", forControlEvents: UIControlEvents.ValueChanged) atableView.addSubview(refreshCntrl) 

// Метод управления обновлением

 func refreshControlValueChanged(){ atableView.reloadData() refreshCntrl.endRefreshing() } 

Начиная с публикации Swift 3.0, даже немного более тонко объявить targetAction соответствующим

 class MyCustomView : UIView { func addTapGestureRecognizer() { // the "_" is important let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(MyCustomView.handleTapGesture(_:))) tapGestureRecognizer.numberOfTapsRequired = 1 addGestureRecognizer(tapGestureRecognizer) } // since Swift 3.0 this "_" in the method implementation is very important to // let the selector understand the targetAction func handleTapGesture(_ tapGesture : UITapGestureRecognizer) { if tapGesture.state == .ended { print("TapGesture detected") } } } 

При использовании функции performSelector()

/addtarget()/NStimer.scheduledTimerWithInterval() ваш метод (соответствующий селектору) должен быть отмечен как

 @objc For Swift 2.0: { //... self.performSelector(“performMethod”, withObject: nil , afterDelay: 0.5) //... //... btnHome.addTarget(self, action: “buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside) //... //... NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector : “timerMethod”, userInfo: nil, repeats: false) //... } @objc private func performMethod() { … } @objc private func buttonPressed(sender:UIButton){ …. } @objc private func timerMethod () { …. } 

Для Swift 2.2 вам нужно написать ‘#selector ()’ вместо имени строки и селектора, чтобы возможности орфографической ошибки и сбоя из-за этого больше не появлялись. Ниже приведен пример

 self.performSelector(#selector(MyClass.performMethod), withObject: nil , afterDelay: 0.5) 

вы создаете селектор, как показано ниже.
1.

 UIBarButtonItem( title: "Some Title", style: UIBarButtonItemStyle.Done, target: self, action: "flatButtonPressed" ) 

2.

 flatButton.addTarget(self, action: "flatButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside) 

Обратите внимание, что синтаксис @selector отсутствует и заменен простой строкой, называя метод вызова. Есть одна область, где мы все можем согласиться с подробностью, полученной на пути. Конечно, если бы мы объявили, что существует целевой метод, называемый flatButtonPressed: лучше написать его:

 func flatButtonPressed(sender: AnyObject) { NSLog("flatButtonPressed") } 

установить таймер:

  var timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("flatButtonPressed"), userInfo: userInfo, repeats: true) let mainLoop = NSRunLoop.mainRunLoop() //1 mainLoop.addTimer(timer, forMode: NSDefaultRunLoopMode) //2 this two line is optinal 

Чтобы быть полным, вот flatButtonPressed

 func flatButtonPressed(timer: NSTimer) { } 

Я нашел многие из этих ответов полезными, но было неясно, как это сделать с чем-то, что не было кнопкой. Я добавлял распознаватель жестов в UILabel в быстром и изо всех сил, поэтому вот что я нашел для меня работающим после прочтения всего выше:

 let tapRecognizer = UITapGestureRecognizer( target: self, action: "labelTapped:") 

Если «Селектор» был объявлен как:

 func labelTapped(sender: UILabel) { } 

Обратите внимание, что это общедоступно и я не использую синтаксис Selector (), но это также можно сделать.

 let tapRecognizer = UITapGestureRecognizer( target: self, action: Selector("labelTapped:")) 

Использование #selector проверит ваш код во время компиляции, чтобы убедиться, что метод, который вы хотите вызвать, действительно существует. Еще лучше, если метод не существует, вы получите ошибку компиляции: Xcode откажется от сборки вашего приложения, тем самым исключая забвение другого возможного источника ошибок.

 override func viewDidLoad() { super.viewDidLoad() navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: #selector(addNewFireflyRefernce)) } func addNewFireflyReference() { gratuitousReferences.append("Curse your sudden but inevitable betrayal!") } 

Может быть полезно отметить, где вы настраиваете элемент управления, который вызывает действие.

Например, я обнаружил, что при настройке UIBarButtonItem мне приходилось создавать кнопку в viewDidLoad, иначе я бы получил исключение исключенного исключения.

 override func viewDidLoad() { super.viewDidLoad() // add button let addButton = UIBarButtonItem(image: UIImage(named: "746-plus-circle.png"), style: UIBarButtonItemStyle.Plain, target: self, action: Selector("addAction:")) self.navigationItem.rightBarButtonItem = addButton } func addAction(send: AnyObject?) { NSLog("addAction") } 

Изменение как простого именования строк в методе, вызывающем синтаксис выбора

 var timer1 : NSTimer? = nil timer1= NSTimer(timeInterval: 0.1, target: self, selector: Selector("test"), userInfo: nil, repeats: true) 

После этого введите func test ().

Для быстрого 3

 let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.test), userInfo: nil, repeats: true) 

Объявление функции в одном classе

 func test() { // my function } 

Для Swift 3

// Пример кода для создания таймера

 Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true) WHERE timeInterval:- Interval in which timer should fire like 1s, 10s, 100s etc. [Its value is in secs] target:- function which pointed to class. So here I am pointing to current class. selector:- function that will execute when timer fires. func updateTimer(){ //Implemetation } repeats:- true/false specifies that timer should call again n again. 
Interesting Posts

Как сделать все объекты в объявлении AWS S3 общедоступными по умолчанию?

Как изменить дизайн фона плеера и цвет для андроида?

Почему существуют орграфы в C и C ++?

Ошибка при использовании LogManager (l4j2) с Java 8 (java.lang.reflect.AnnotatedElement не может быть разрешена)

Должен ли я использовать #include рядом с ?

Async Void, ASP.Net и количество неиспользуемых операций

Как скрыть всплывающую подсказку при наведении курсора из тега заголовка при использовании FancyBox 2.0?

Значение нового classа (…) {{…}} Инициализация idiom

Поддержка SQLAlchemy схем Postgres

Краткое объяснение Async / Await в .Net 4.5

Как установить выбранную опцию выпадающего списка с использованием углового JS

Инициализировать защищенные члены родителя с помощью списка инициализации (C ++)

Как выравнивать представления в нижней части экрана?

По какой причине я не могу создавать общие типы массивов в Java?

Отключение выбора текста в PhoneGap

Давайте будем гением компьютера.