Nick Harris

Selectors With Parameters in Swift 2.2

with 16 comments

I went back today and recompiled all my latest Swift projects  – Euchre, CloudKitPOC, Suntracker, Solitaire – to see how much Swift 2.2 would break them. The only thing that I got warnings about (I’m a 0 warnings dev) was about changing from string selectors to using the #selector() syntax. They were all warnings but I had problems fixing one of them. The “Fix-it” solution ended up being another warning.

In Solitaire I have a GameController and a GameViewController. The GameViewController is strictly UI only. There is no game logic what-so-ever in it. All of that is contained in the GameController. I also created a PlayingCardImageView subclass of UIImageView to handle all the interaction with the playing cards. For instance, tapping a playing card will execute any plays that card can make in the game.

When implementing this, I had to decide if I wanted pass the GameController into every PlayingCardImageView or have the target and selector of the UITapGestureRecognizer refer back to the GameViewController. I opted for the later. I only wanted one class to be responsible for passing user interactions back to the GameController.

My code in the PlayingCardImageView for 2.1 was:

let tapGestureRecognizer = UITapGestureRecognizer(target: gameViewController, action: "cardTapped:")
self.addGestureRecognizer(tapGestureRecognizer)
 

The “Fix-it” solution:

Screen Shot 2016 03 22 at 9 07 33 PM

which then lead to…

Screen Shot 2016 03 22 at 9 12 24 PM

Hopefully the first thing you’re thinking as a seasoned Xcode user is “Never use Fix-it!!” and you’d be right. Unless you understand what Fix-it is actually doing its much better to dig into the problem yourself and figure out what the fix should be.

The proper solution in Swift 2.2 for this is:

let tapGestureRecognizer = 
UITapGestureRecognizer(target: gameViewController, action: #selector(gameViewController.cardTapped(_:)))
self.addGestureRecognizer(tapGestureRecognizer)
 

It wasn’t the most obvious syntax to arrive at but at least I know now.

BTW – here’s a great rundown of Swift 2.2 changes. I’m looking forward to trying out tuple comparisons – particularly with my NSOperation operationResult tuples in unit tests.

Update

I want to point out that I figured it out quite easily with Xcode code completion. I don’t want this post to sound like a dump on the Xcode team. Xcode gets better and better with every release! I bet its just a miss in the Fix-it logic.

Screen Shot 2016 03 22 at 10 03 02 PM 

Advertisements

Written by Nick Harris

March 23, 2016 at 3:37 am

Posted in Uncategorized

16 Responses

Subscribe to comments with RSS.

  1. Helpful advice, I’m glad you included the image of the completion though as the actual code you posted is running off the edges in Safari and is very hard to read during the key bit!

    ktest098

    March 23, 2016 at 3:59 pm

  2. My experience is a bit different. If Fix-it offers “#selector(…)” then take it. But if the selector is not in the same scope, Fix-it gets confused and you need to fix it manually.

    I think “never use Fix-it” is no longer good advice as it gets better with every new version of Xcode.

    Sarah

    March 23, 2016 at 8:28 pm

    • You’re right and I agree that never use fix-it is no longer good advice. I guess my point was to also understand what the fix is and why. I initially thought that Selector() was OK to use but after digging around I understood that #selector() is the correct syntax.

      Nick Harris

      March 23, 2016 at 8:42 pm

  3. Great article. How to pass parameter in selector 2.2

    Anonymous

    March 24, 2016 at 6:36 am

  4. So… where’s the parameter stuff? It’s in the title of the article, but nowhere else. Maybe fix your mess and rename it with “Selectors in swift 2.2” because this has *nothing* to do with selectors with parameters. Misleading is not good.

    Eugen

    April 19, 2016 at 10:00 am

    • Hi Eugen. The parameter I’m referring to is the UIGestureRecognizer parameter that is passed to the selector. The signature of that function is:

      func cardTapped(gestureRecognizer: UIGestureRecognizer)

      When assigning the selector the gestureRecognizer parameter is represented as:

      #selector(gameViewController.cardTapped(_:))

      I’m sorry you were confused. Hopefully that clarifies my intent.

      Nick Harris

      April 19, 2016 at 2:27 pm

      • Confused and angry. Let’s say I have this function:
        func makeCardForPerson(name: String, age: Int, image: UIImage) {

        }

        I want to use it as a selector:
        #selector(self.makeCardForPerson(_:age:image:))

        The problem is that I cannot use values for those parameters (name, age, image). Inside the function makeCardForPerson I want to be able to use name, age and image, but how can I do that from a selector if I cannot assign values for them? 😦

        I was hoping to get an answer here because I saw the title (selectors with parameters), that’s why I got mad when I saw it’s not what I was looking for.

        Eugen

        April 20, 2016 at 7:27 am

    • Eugen,

      I can get your selector to work by not using ‘self’ in the selector description but the name of the containing class.

      If the makeCardForPerson(_:age:image:) function is in ViewController, you can use something like this:

      let selector = #selector(ViewController.makeCardForPerson(_:age:image:))

      Xcode will auto-complete once you have entered the class name and the start of the function name.

      Sarah

      April 20, 2016 at 8:33 am

      • Thank you Sarah! Great answer!

        Nick Harris

        April 21, 2016 at 5:35 am

  5. My apologies. The title was just what I was dealing with when I wrote the post.

    Are you still looking for a solution? Its pretty late my time right now but I’d be happy to dive into it in the morning. If you’ve found a solution I’d be happy to add a post script with a better answer.

    And thank you for the dialog. I truly appreciate it.

    Nick Harris

    April 20, 2016 at 7:55 am

    • Yes, I’m still looking for a solution. I found a few ways to solve this, but it’s more complex than I want and they all require more resources. Thank you. I also appreciate the discussion.

      Eugen

      April 20, 2016 at 10:31 am

      • Did Sarah answer your questions?

        Nick Harris

        April 21, 2016 at 5:34 am

  6. My problem is not how to call the selector, but how to pass the values for parameters. I already wrote the syntax, so that’s not the problem. Look at the code bellow:

    func updatePlayer(name: String, statement: String, gold: Int) {
    print(“\(name) \(statement) \(gold) gold”)
    }

    func iCanDoThis() {
    updatePlayer(“John”, statement: “won”, gold: 25)
    }

    func myProblem() {
    let imageView = UIImageView()
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.updatePlayer(_:statement:gold:)))
    imageView.userInteractionEnabled = true
    imageView.addGestureRecognizer(tapGestureRecognizer)
    }

    In the function iCanDoThis it’s very easy to use the updatePlayer function, I will get in console “John won 25 gold”. But if I try to use the same function as a selector in myProblem what will happen when I tap on the imageView? I cannot tell the selector what are the values for the parameters.

    So I ask again. What’s the point of having those parameters if you cannot actually use them?

    Eugen

    April 21, 2016 at 7:28 am

  7. Thanks. I’ve already tried making a custom UIImageView class with the parameters I need, but for some reasons the selector is not called. I’ve also tried with a custom UIButton class (setting image for button the image inside imageView), then I used addTarget for button. But I got the same result, selector is not called (I tried with selector inside the custom class, also with selector inside the class that use the custom class).

    It should work, but it doesn’t 😦

    Anyway, this way of calling selectors (without being able to pass real values for parameters) is really stupid, what is apple thinking? But hey, it’s apple, we don’t need Home/End/Delete/PgUp/PgDown keys on the keyboards, so why should we need other basic things…

    Thanks again Nick.

    Eugen

    April 22, 2016 at 12:22 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: