@ selector () в Swift?
Я пытаюсь создать NSTimer
in 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())
но ничего не работает и я не могу найти решение в ссылках.
21 ответ:
Свифт не использует селекторы-несколько шаблонов проектирования, которые в Objective-C используют селекторы, работают по-разному в Swift. (Например, используйте необязательную цепочку для типов протоколов или
is
/ тестыrespondsToSelector:
, и использовать закрытие везде, где вы можете вместоperformSelector:
для лучшей безопасности типа / памяти.)но есть еще ряд важных API-интерфейсов на основе ObjC, которые используют селекторы, включая таймеры и шаблон цели/действия. Быстрый обеспечивает
Selector
тип для работы с этими. (Swift автоматически использует это вместо ObjCSEL
тип.)в 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+ для именования типов функций.(это на самом деле улучшение по сравнению с ObjC
@selector()
директива, потому что компилятор-Wundeclared-selector
проверка проверяет только то, что именованный селектор существует. Ссылка на функцию Swift, которую вы передаете в#selector
проверяет существование, членство в классе и подпись типа.)есть несколько дополнительных предостережений для ссылок на функции, которые вы передаете в
#selector
выражение:
- несколько функций с одинаковым базовым именем могут быть дифференцированы по их меткам параметров с использованием вышеупомянутого синтаксис для ссылок на функции (например,
insertSubview(_:at:)
vsinsertSubview(_:aboveSubview:)
). Но если функция не имеет параметров, единственный способ устранить неоднозначность-использоватьas
cast с сигнатурой типа функции (например,foo as () -> ()
vsfoo(_:)
).- в 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, должен иметь свое объявление, предшествующее . (В предыдущих версиях вы получили этот атрибут бесплатно в некоторых случаях, но теперь вы должны явно объявить его.)
помните, что
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
класс на 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) класс не происходит от класса Objective-C, то вы должны иметь двоеточие в конце строки имени целевого метода, и вы должны использовать свойство @objc с вашим целевым методом, например
var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method")) @objc func method() { // Something cool here }
в противном случае вы получите ошибку "нераспознанный селектор" во время выполнения.
для будущих читателей, я обнаружил, что я испытал проблему и получал
unrecognised selector sent to instance
ошибка, вызванная пометкой целиfunc
как частное лицо.The
func
должны быть публично видимым для вызова объекта со ссылкой на селектор.
Swift 2.2+ и Swift 3 Обновление
использовать новый
#selector
выражение, которое устраняет необходимость использовать строковые литералы делает использование менее подверженным ошибкам. Для справки:Selector("keyboardDidHide:")
становится
#selector(keyboardDidHide(_:))
Читайте также: Быстрое Эволюционное Предложение
Примечание (Swift 4.0):
при использовании
#selector
вам нужно будет пометить функцию как@objc
пример:
@objc func something(_ sender: UIButton)
на случай, если у кого-то еще есть та же проблема, что и у меня с NSTimer, где ни один из других ответов не исправил проблему, действительно важно упомянуть, что если вы используете класс, который не наследует от NSObject ни напрямую, ни глубоко в иерархии(например, вручную созданные swift-файлы), ни один из других ответов не будет работать, даже если указан следующим образом:
let timer = NSTimer(timeInterval: 1, target: self, selector: "test", userInfo: nil, repeats: false) func test () {}
Не меняя ничего, кроме как просто сделать класс наследуется от NSObject я остановился получение ошибки "нераспознанный селектор" и получил мою логику работы, как ожидалось.
Swift 4.0
создать селектор, как показано ниже.
1.добавьте событие в кнопку, например:
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) }
включите двоеточие в текст селектора (tester:), и ваши параметры перейдут в userInfo.
ваша функция должна принимать NSTimer в качестве параметра. Затем просто извлеките userInfo, чтобы получить переданный параметр.
селекторы-это внутреннее представление имени метода в Objective-C. В Objective-C "@selector(methodName)" преобразует метод исходного кода в тип данных SEL. Поскольку вы не можете использовать синтаксис @selector в Swift (там находится rickster), вам нужно вручную указать имя метода как строковый объект напрямую или передать строковый объект в тип селектора. Вот пример:
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") )
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) }
см. документ Apple для получения более подробной информации о: Выражение Селектора
// 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 }
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() }
поскольку Свифт 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 в swift и боролся, поэтому вот что я нашел, работало для меня после прочтения всего выше:
let tapRecognizer = UITapGestureRecognizer( target: self, action: "labelTapped:")
где "селектор" был объявлен:
func labelTapped(sender: UILabel) { }
обратите внимание, что он является общедоступным и что я не использую синтаксис Selector (), но это также можно сделать.
let tapRecognizer = UITapGestureRecognizer( target: self, action: Selector("labelTapped:"))
С помощью #селектора проверит ваш код во время компиляции, чтобы убедиться, что метод, который вы хотите вызвать, действительно существует. Еще лучше, если метод не существует, вы получите ошибку компиляции: 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 ().
для swift 3
let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.test), userInfo: nil, repeats: true)
Объявление Функции В Том Же Классе
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.