Swift 3 UITableViewDataSource selectors - ios

After updating to Swift 3 I get error in following code:
extension MyViewController: UITableViewDataSource {
//...
func tableView(_ tableView: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat {
return someValue
}
}
Objective-C method 'tableView:heightForRowAt:' provided by method
'tableView(_:heightForRowAt:)' does not match the requirement's
selector ('tableView:heightForRowAtIndexPath:')
It can be fixed with
#objc(tableView:heightForRowAtIndexPath:)
func tableView(_ tableView: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat {
return someValue
}
Could anyone explain motivation of signature changing in new version of Swift? There is no info in migration guide about it.

With the release of Swift 3.0 the signatures of many methods in the library have been changed for the sake of readability (see API Design Guidelines).
Compare for example the current signature of the method you quoted to its representation in the code completion suggestions list of Xcode:
// implementation:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {...}
// code completion:
tableView(tableView: UITableView, heightForRowAt: IndexPath)
In contrast the previous implementation used to show redundant information:
// implementation:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {...}
// code completion:
tableView(tableView: UITableView, heightForRowAtIndexPath: NSIndexPath)
--------- -----------
Furthermore the implementation of a function or method now requires an underscore (_) to be set even for the first argument in order to allow omitting argument labels when calling the function/method (see: https://stackoverflow.com/a/38192263/6793476).
Obviously some selectors in the library haven't been updated yet so you need to provide proper ("the old") selector names (see: https://stackoverflow.com/a/39416386/6793476 and for more information about selectors: https://stackoverflow.com/a/24007718/6793476).
I hope that helps.

Related

Reordering table rows using UITableViewDataSource methods does not work

I'm trying to play a reorder animation that should be called by the methods below, I guess
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
true
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
}
But for some reason, no animation followed. Most likely, I missed something, how exactly to trigger the animation of changing the order of the cells.
I found the missing component. The reason for which the animation of moving cells did not start. It's the lack of a setting:
tableView.isEditing = true

Fix for getting "deprecated and will be removed in Swift 4" warning for tableView functions

I just upgraded my codes to Swift 4 and now receiving this warning on console for all tableView function.
tableView:willDisplayCell:forRowAtIndexPath:] is deprecated and will be removed in Swift 4; add explicit '#objc' to the declaration to emit the Objective-C entrypoint in Swift 4 and suppress this message
tableView:cellForRowAtIndexPath:] is deprecated and will be removed in Swift 4
Use below code for cellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}
Use below one to identify cells which are displaying
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
}
if you have doubt regarding datasource and delegate function select UITableViewDataSource or UITableViewDelegate and right click jump to definition that will lead to get your functions
Hope this will help you
I'm not recommend anone to fix this problem like this but it did worked for me.
You could add "#objc" at the beginning of every tableView function You use.
Like this:
#objc func tableView(_ tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return 1
}

Swift 3.0 Conversion UITableView Not Calling Methods In UITableViewController [duplicate]

I have updated my code to swift 3.0 and get a warning on the following line:
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell {
When I try each of the suggestions to either silence the warning with #nonobjc or make it a private function the table no longer loads.
The error reads:
Instance method 'tableView(:cellForRowAtIndexPath:)' nearly matches optional requirement 'tableView(:canFocusRowAt:)' of protocol 'UITableViewDelegate'
Does anyone know what causes this error and how to fix it?
Many thanks!
Just add the declaration of implementing UITableViewDataSource protocol to the class definition like this:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {}
In swift 3.0 the signature for the datasource changed to:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
Notice the difference between cellForRowAtIndexPath indexPath: IndexPath and cellForRowAt indexPath: IndexPath
I'm using the new method without any warnings, hope this will solve your problem.
Cheers.
I had a similar problem, and found that if you remove the space between the underscore before tableView, from this
func tableView(_ tableView: ...
to this
func tableView(_tableView: ...
strangely the warning goes away...

UITableview: failed to obtain a cell from its dataSource

I get this error message: failed to obtain a cell from its dataSource
The strange that
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
not even get called, problem is not that returned cell is nil. I put in breakpoints. cellForRowAtnot get called.
numberOfRowsInSection returns value.
I do not know it is relating or not, but now I do not use UITableViewController, I just have a UIViewController, and it is the datasource and delegate for the UITableView. I hope it can not cause interfere. Any idea?
Cross check below check list:-
it's because you are failing to dequeue a reusable cell.
The problem is that your cellForRowAtIndexPath function is embedded in another function
when you forgot to add the UITableViewDataSource and UITableViewDelegate protocols to the ViewController declaration.
class DataViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
I guess this is your problem - Failed to obtain a cell from its DataSource
you can take a look at: https://www.hackingwithswift.com/example-code/uikit/fixing-failed-to-obtain-a-cell-from-its-datasource
try something like this:
cell = tableView.dequeueReusableCellWithIdentifier(getCellIdentifierForType(cellType))
setDataToCell(cell, item: item)
good luck
Please make sure when you are migrating your code from swift older to new versions then your tableview data source and delegates have updated syntax.
For example
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
and
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
Can not auto updated to below:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

Swift 3: Understand syntax change for UITableViewDataSource method

I have some questions with Swift 3 function calling. Below is an example.
Old Swift:
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell
Swift 3:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
That's fine with the above syntax. But now Xcode shows me an error and asks me to do like below:
#objc(tableView:cellForRowAtIndexPath:) func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
I do not understand why I have to declare #objc(tableView:cellForRowAtIndexPath:).
This is happening only when I am trying to implement table view datasource methods under an extension. Also this is not happening for numberOfRowsInSection or viewForHeaderInSection.
Can anyone help me to understand why this is happening?
While I am not sure what triggers the #objc, I can suggest the following approach:
Store the tableView variable somewhere in the viewDidLoad:
let tv = tableView!
Then hover over the tableView variable and press the command button in conjunction with a click.
This should take you to the interface of a UITableView.
Then, hover over either UITableViewDelegate or UITableViewDataSource and press the command button in conjunction with a click.
Now you can see the new signatures.
A lot has changed...Happy upgrade!
Swift compiler forced to write Objc(funcName) before function if you are using this function from Objective c. According to app doc
Use the #objc(name) attribute to provide Objective-C names for
properties and methods when necessary. For example, you can mark a
property called enabled to have a getter named isEnabled in
Objective-C like this:
var enabled: Bool {
#objc(isEnabled) get {
// ...
}
}
To void this, use extension to write TableView Datasource and delegate
extension YourViewControllerName:UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell() as SplitAddContactCell
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80.0
}
}

Resources