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())
しかし何もうまくいきません、そして私は参考文献の中に解決策を見つけることができません。
Swiftitselfはセレクターを使用しません。Objective-Cでセレクターを使用するいくつかのデザインパターンは、Swiftで異なる動作をします。 (たとえば、プロトコルタイプでオプションのチェーンを使用するか、respondsToSelector:
の代わりにis
/as
テストを使用し、performSelector:
の代わりにできる限りクロージャーを使用して、タイプ/メモリの安全性を高めます)
ただし、タイマーやターゲット/アクションパターンなど、セレクターを使用する多くの重要なObjCベースのAPIがまだあります。 Swiftは、これらを操作するためのSelector
タイプを提供します。 (SwiftはObjCのSEL
タイプの代わりにこれを自動的に使用します。)
#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:)
vs insertSubview(_:aboveSubview:)
)を使用して、パラメーターラベルで区別できます。しかし、関数にパラメーターがない場合、それを明確にする唯一の方法は、関数の型シグネチャでas
キャストを使用することです(例:foo as () -> ()
vs foo(_:)
)。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にあるもの なので、適切な場合はセレクターの代わりに正しいKeyPathベースのAPIを使用していることを確認してください。
セレクタの詳細については、 Objective-C APIとの対話 inUsing Swift with Cocoa and Objective-Cを参照してください。
注:Swift 2.2より前、Selector
はStringLiteralConvertible
に準拠していたため、古いコードを見つけることができます。セレクターを使用するAPIに裸の文字列が渡されます。 Xcodeで「現在のSwift構文に変換」を実行して、#selector
を使用するものを取得する必要があります。
SwiftでSelector
クラスを使用する方法の簡単な例を示します。
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
}
それ以外の場合は、実行時に "認識できないセレクタ"エラーが発生します。
Swift 2.2以降およびSwift 3アップデート
新しい#selector
式を使用します。これにより、文字列リテラルを使用する必要がなくなり、使用率が低下する可能性が少なくなります。参考のため:
Selector("keyboardDidHide:")
になる
#selector(keyboardDidHide(_:))
また見なさい: 速い進化の提案
注(Swift 4.0):
#selector
を使用する場合は、関数を@objc
としてマークする必要があります。
例:
@objc func something(_ sender: UIButton)
将来の読者のために、私は問題を経験し、ターゲットfunc
を非公開としてマークすることによって引き起こされるunrecognised selector sent to instance
エラーを得ていたことを知りました。
func
MUSTは、セレクタへの参照を持つオブジェクトによって呼び出されるように一般に公開されている必要があります。
Swift 4.0
以下のようにセレクタを作成します。
1.イベントをボタンに追加します。
button.addTarget(self, action: #selector(clickedButton(sender:)), for: UIControlEvents.touchUpInside)
そして機能は以下のようになります。
@objc func clickedButton(sender: AnyObject) {
}
他の誰かが私と同じ問題を抱えていて他の答えで問題が解決されない場合に備えて、NSObjectから直接継承していないクラスや階層の奥深くまで継承していないクラスを使用している場合たとえば、手動で作成されたSwiftファイル)、次のように指定されていても他の答えはどれもうまくいきません。
let timer = NSTimer(timeInterval: 1, target: self, selector: "test",
userInfo: nil, repeats: false)
func test () {}
単にクラスをNSObjectから継承させる以外に何も変更することなく、「認識されないセレクタ」エラーが発生するのをやめ、予想通りにロジックを動作させることができました。
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のデータ型に変換します。 Swiftでは@selector構文は使用できないため(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: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()
}
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)
#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!")
}
私はこれらの答えの多くが有用であると思いました、しかしそれがボタンではなかった何かでこれをする方法を明らかにしませんでした。私はSwiftのUILabelにジェスチャー認識機能を追加して苦労したので、上記のすべてを読んだ後に私がうまくいったのは次のとおりです。
let tapRecognizer = UITapGestureRecognizer(
target: self,
action: "labelTapped:")
「セレクタ」は次のように宣言されています。
func labelTapped(sender: UILabel) { }
これは一般に公開されているので、私はSelector()構文を使用していませんが、これを実行することも可能です。
let tapRecognizer = UITapGestureRecognizer(
target: self,
action: Selector("labelTapped:"))
以下のようにセレクタを作成します。
1。
UIBarButtonItem(
title: "Some Title",
style: UIBarButtonItemStyle.Done,
target: self,
action: "flatButtonPressed"
)
2。
flatButton.addTarget(self, action: "flatButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
@selector構文は廃止され、呼び出すメソッドの名前を表す単純なStringに置き換えられました。私たち全員が邪魔になった冗長性に同意できる分野が1つあります。もちろん、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) {
}
アクションをトリガーするコントロールをどこに設定するかをメモしておくと便利です。
たとえば、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 4のセレクター:
button.addTarget(self, action: #selector(buttonTapped(sender:)), for: UIControlEvents.touchUpInside)
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.
Swift 3の場合
let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.test), userInfo: nil, repeats: true)
関数宣言同じクラス内:
@objc func test()
{
// my function
}