Fayyouz
Fayyouz

Reputation: 682

Argument of '#selector' does not refer to an '@objc' method (swift 3)

I am setting up swipe recognition in my SKScene, and I found that hard coding all the recognizers takes time and isn't really neat, so I decided to use a for-loop, and a dictionary that contains UISwipeRecognizers as keys, and () functions as values. The problem is that it gives me the error in the title while trying to add the target using recognizer.addTarget(self, action: #selector(functionForRecognizer[recognizer]!))

Here is the code:

class xxxxx: SKScene {

let rightSwipeRecognizer = UISwipeGestureRecognizer()
let leftSwipeRecognizer = UISwipeGestureRecognizer()
let upSwipeRecognizer = UISwipeGestureRecognizer()
let downSwipeRecognizer = UISwipeGestureRecognizer()

var swipeRecognizers: [UISwipeGestureRecognizer] {
    return [rightSwipeRecognizer, leftSwipeRecognizer, upSwipeRecognizer, downSwipeRecognizer]
}

var directionForRecognizer: [UISwipeGestureRecognizer : UISwipeGestureRecognizerDirection] {
    return [
        rightSwipeRecognizer : .right,
        leftSwipeRecognizer : .left,
        upSwipeRecognizer : .up,
        downSwipeRecognizer : .down
    ]
}

func didSwipeRight() {}
func didSwipeLeft() {}
func didSwipeUp() {}
func didSwipeDown() {}

var functionForRecognizer: [UISwipeGestureRecognizer : ()] {
    return [
        rightSwipeRecognizer : didSwipeRight(),
        leftSwipeRecognizer : didSwipeLeft(),
        upSwipeRecognizer : didSwipeUp(),
        downSwipeRecognizer : didSwipeDown()
    ]
}

func setupSwipeRecognizers() {
    for recognizer in swipeRecognizers {
        recognizer.addTarget(self, action: #selector(functionForRecognizer[recognizer]!))
        recognizer.direction = directionForRecognizer[recognizer]!
        self.view?.addGestureRecognizer(recognizer)
    }
}

override func didMove(to view: SKView) {
    super.didMove(to: view)
    setupSwipeRecognizers()
}

}

Btw, i tried putting @objc while declaring the functions, but it didn't work. Also, I tried exposing the class to NSObject, by removing inheritance from SKScene and conforming to NSObject, and still, it didn't work. Moreover, i cannot conform the class to a UIKit class, cz i need it as a SKScene, and even, i tried conforming it to a UIViewController (without SKScene, of course), but still didn't work,

Upvotes: 3

Views: 2700

Answers (1)

allenh
allenh

Reputation: 6622

What you are trying to do isn't possible with Swift's #selector. Instead, insert instances of the Selector class directly into the dictionary.

You'll also need to annotate with @objc

@objc // This annotation isn't required in Swift 3, but will be in Swift 4
func didSwipeRight() {}

var functionForRecognizer: [UISwipeGestureRecognizer : Selector] {
    return [
        rightSwipeRecognizer : #selector(didSwipeRight)
    ]
}

recognizer.addTarget(self, action: functionForRecognizer[recognizer]))

For a detailed explanation of #selector see this answer. Summary, #selector is a compiler construct for Swift that ensures the exact selector/method exists, including the class it should exist on. It looks at the actual contents within its parentheses to see if it is a known method, and functionForRecognizer[recognizer] is not a method name, it is a variable + subscript method call.

Upvotes: 4

Related Questions