0

The code completion fills in the name of the method inside the #selector( then proceeds to crash at runtime with an error that the selector is unrecognized, (IllegalArgumentException).

What was the point of redoing the selector syntax as no longer just strings??

Here is the creation of the selector:

headerAddButton.addTarget(section, action: #selector(addActivityToSpecificDay(sender:)), for: .touchDown)

Section (referenced here) is the header section of the tableview (forgot to mention, this code was working before Xcode 9):

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

Here is the method signature of the handler:

@objc func addActivityToSpecificDay (sender :UIButton)

In the same source file of course. But read the question: if the code completion can find it how on earth do I get a runtime crash?

Rob
  • 11,446
  • 7
  • 39
  • 57
  • Is your method tagged with `@objc`, overriding a method tagged with `@objc`, or satisfying the requirement of an `@obj` protocol? – vacawama Nov 30 '17 at 00:16
  • 1
    Show your code. – creeperspeak Nov 30 '17 at 00:17
  • Yes it has @objc – Rob Nov 30 '17 at 00:22
  • Is the function in the class represented by `section`? – rmaddy Nov 30 '17 at 00:26
  • 1
    Is `section` an instance of the class where `addActivityToSpecificDay` is defined? – vacawama Nov 30 '17 at 00:26
  • @vacawama good call, I updated the question to include the section definition – Rob Nov 30 '17 at 00:29
  • What is the error? – Hot Licks Nov 30 '17 at 00:35
  • 2
    You seem to have missed the point of the question both I and @vacawama asked. Your addTarget call is claiming that the class represented by `section` has the function `addActivityToSpecificDay`. But clearly that's not true. That function is in your view controller class, not the view class used for your section header. – rmaddy Nov 30 '17 at 00:38
  • I got that. I did not write this code. I was just asked to look at it when it caused a crash today. How did this code ever work? I looked at blame and it was this way and worked before. – Rob Nov 30 '17 at 03:56
  • Silent downvotes. I thought about editing the title of this but I do think it is a valid question: if they went to the trouble to destringify selectors, and add code completion, why does it offer me a syntax that will fail at runtime? Clearly exactly what a helper tool should never do. – Rob Dec 05 '17 at 23:28

1 Answers1

3

You are adding the target like so:

headerAddButton.addTarget(section, action: #selector(addActivityToSpecificDay(sender:)), for: .touchDown)

Because your #selector doesn't qualify addActivityToSpecificDay with a class, it is obviously matching up with some method of that name in the current class, not in whatever class section is.

There are two options:

  1. Move addActivityToSpecificDay into whatever class section is (for the purposes of illustration, let's say it was SectionClass) and reference that class in your #selector:

    headerAddButton.addTarget(section, action: #selector(SectionClass.addActivityToSpecificDay(sender:)), for: .touchDown)
    
  2. Or keep addActivityToSpecificDay in the current class, but change the target of addTarget to self:

    headerAddButton.addTarget(self, action: #selector(addActivityToSpecificDay(sender:)), for: .touchDown)
    

You ask:

What was the point of redoing the selector syntax as no longer just strings??

It validates that the selector’s function exists and is well formed (which is a very good thing), but it obviously cannot validate that the selector’s class happens to be the same class as some other parameter (the target in this example). The compiler can’t reliably know how the addTarget method uses the selector nor that there is some special relationship between two parameters. That is left to the developer. The #selector syntax helps, but it is not a magic bullet.

Rob
  • 415,655
  • 72
  • 787
  • 1,044