Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift default parameter & Selector Syntax

I have a function that takes a default parameter:

func myFunc(foo: Bool = true) { }

I'm trying to figure out the correct Selector syntax for it as I'm adding it as a target for a UIRefreshControl

 self.refreshControl.addTarget(self, action: Selector("myFunc"), forControlEvents: UIControlEvents.ValueChanged)

I have tried both Selector("myFunc") and Selector("myFunc:") - both crash with invalid selector error.

Had a scour of the web but no solutions were thrown up. Can someone assist? Thanks

like image 710
cud_programmer Avatar asked Mar 01 '15 13:03

cud_programmer


2 Answers

We are trying to add an action to a UI element. Consider the options that Xcode presents us with if we try to hook up a control from our interface builder file to our view controller class:

enter image description here

Much like the method you're using, Interface Builder is asking us for multiple things.

  • Interface builder knows which control is the sender (where we initiated the Ctrl+drag from... this equates to your self.refreshControl which is what we're calling addTarget on).
  • Interface builder knows what class is the target (we Ctrl+dragged to it).
  • Interface builder asks for the name of a method we're about to create. In your case, you chose that when you wrote the method.
  • Interface builder asks us how the sender should be passed. It gives us, in the case of a button, the option of AnyObject (default) or UIButton. In the case of a UIRefreshControl, the options would be AnyObject or UIRefreshControl. This is passed as the "sender" object.
  • Interface builder asks us for which events should this method be called (just as the addTarget method does).

And finally, Interface builder asks us what sorts of arguments should be passed:

enter image description here

We have three options here.

We can pass no arguments, in which case, we'd have a method that looks like this:

func myFunc() {

}

Or we can pass the "sender", in which case the method would look like this:

func myFunc(sender: AnyObject) {

}

But the type of sender will vary depending on what we actually try to send.

Or we could pass the sender and the event type (useful if multiple events are tied to the same method):

func myFunc(sender: AnyObject, forEvent event: UIEvent) {

}

If done through Interface builder, we'll also have an @IBAction stuck out at the beginning, but that's not what we're doing in your example.

Now, if this were Objective-C, our method would look something like this:

- (void)myFunc:(id)sender {

}

And Objective-C does not support overloading, so it would not allow another function in the same class that looks like this:

- (void)myFunc:(BOOL)foo {

}

You can't have two methods with the same name.

Swift, however, does support method overloading, and as such, the same class could have both of the following methods:

func myFunc(foo: AnyObject) {

}

func myFunc(foo: Bool) {

}

These are entirely different methods in the eyes of Swift, and perfectly fine.

Your code, however, only has the latter. A method called myFunc which takes a Bool argument.

When you try to add the addTarget: method, Swift is looking for a method with the name you gave it (myFunc:) which can accept a UIRefreshControl argument. It can't find an overload.

Effectively, the error you are getting is sort of the same as this error:

enter image description here

The point is, Swift can't find a method called myFunc: that can accept a UIRefreshControl argument.

like image 196
nhgrif Avatar answered Nov 03 '22 01:11

nhgrif


You're getting a crash because it expects a different parameter. 'addTarget' expects to get a function who's sole parameter (if any) is AnyObject (or maybe UIView), not Bool

like image 2
Shai Avatar answered Nov 03 '22 01:11

Shai