3
votes

I'm having trouble understanding what this error means. My app was working fine until I migrated up to Swift 4. Now I'm getting this tableView:numberOfRowsInSection error when trying to open several of my view controllers. I didn't get any of these errors in Swift 3.2. The numberOfRowsInSection method has been implemented in all cases, and appears fine. Can anyone point me in the right direction?

2017-11-26 10:21:04.973523-0600 Y2GOsp[27701:6382461] -[Y2GOsp.ClientDetailViewController tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0x7fa51c89f000 2017-11-26 10:21:43.328635-0600 Y2GOsp[27701:6382461] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Y2GOsp.ClientDetailViewController tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0x7fa51c89f000'

numberOfRowsInSection implementations:

Example 1:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 1
}

Example 2:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return dayAppoints.count
}
2
Add your numberOfRowsInSection implementation to the question. - vacawama
Are you aware that you wrote tableview:… instead of tableView:…? - vikingosegundo
Does adding @objc before the func declaration make it work? - vacawama
Does your class state its conformance to UITableViewDataSource? If it does, Swift should infer (and require) that your implementation(s) of the @objc protocol requirements are also @objc. It would help if you could provide some more context. - Hamish
That would explain it. I'm surprised that Swift didn't complain when you assigned the delegate. - vacawama

2 Answers

15
votes

@Hamish identified the issue in his comment. You forgot to add UITableViewDataSource to your class declaration. Because of that, your data source methods were not exposed to Objective-C.

My suggestion to try adding @objc to the methods confirmed the issue.

The reason this worked in Swift 3 was that all methods of classes that derived from NSObject (which UIViewController does) were available to Objective-C.

In Swift 4 (due to SE-0160), it is necessary to explicitly tag functions with @objc that will be called through a selector unless you are overriding a function that is so marked in the base class, or in this case if the functions satisfy the requirement of an @objc protocol definition.

0
votes

I had the same issue and I followed vacawama suggestions. But instead of adding @objc before every delegated method (I find the @objc tags very ugly), I made my ViewController implement the UITableViewDataSource and UITableViewDelegate protocols (I have a generic VC containing a UITableView) and assigned my ViewController to his tableView explicitely as a datasource and delegate:

self.tableView.delegate = self
self.tableView.dataSource = self

and it works like a charm, without ugly @objc tags. In fact, I originally assigned the delegate and datasource to the tableView using the InterfaceBuilder (via ctrl + click)