When should iOSTableDataSource.RowData be called?

In what circumstances should iOSTableDataSource.RowData be called?

My understanding was that, if iOSTable.EstimatedRowHeight is set for the data source’s table, iOSTableDataSource.RowData should only be called when the app needs to display data. Instead, when opening a view with a table with a large data set, it’s being called once per row and causing performance problems.

Interestingly, after the initial load, when the data set is changed (e.g. because the user performs a search), iOSTableDataSource.RowData is only called for the displayed rows.

Does anyone have any tips for avoiding having iOSTableDataSource.RowData called for every row in a data set?

I followed the iOSTable examples in my app. I have a ton of different table datasources and all.

This is basically how the examples said to do it. My datasets aren’t that large but

Public Function RowData(table as iOSTable, section As Integer, row As Integer) as iOSTableCellData
  // Part of the iOSTableDataSource interface.
  Select Case section
  Case 0
    Dim GroupNames() As Text
    For Each d As DictionaryEntry In GroupList
      GroupNames.Append d.Value
    If row <= GroupNames.Ubound Then
      Dim cell As iOSTableCellData = table.CreateCell
      cell.Text = GroupNames(row)
      Dim currentname as Text = GetCurrentTextCallBack
      If CurrentName = cell.Text Then
        cell.AccessoryType = iOSTableCellData.AccessoryTypes.Checkmark
        cell.AccessoryType = iOSTableCellData.AccessoryTypes.None
      End If
      Return cell
    End If
  End Select
End Function

And when the user clicks on a Cell, the Action method that is using the dataset does something like this:

If GroupIndex <> -1 Then
  Dim SelectedCell As iOSTableCellData = GroupTable.RowData(0, GroupIndex)
  SelectedCell.AccessoryType = iOSTableCellData.AccessoryTypes.Checkmark
End If

For i As Integer = 0 To GroupTable.RowCount(0)-1
  If i <> GroupIndex Then
    GroupTable.RowData(0,i).AccessoryType = iOSTableCellData.AccessoryTypes.None
  End If

RaiseEvent Action(GroupIndex)

I don’t think I’m seeing any case where it’s being called on every single row… I’m looking through my code right now for RowData and I only see it called after an Action.

I figured this is the way Xojo says to do it…

Yes, RowData is only called in the Action event in your code.

BTW, I keep the data in an array elsewhere. You’ve got extra overhead by building the GroupNames array every time you draw a row.

Public Function RowCount(table as iOSTable, section As Integer) as Integer
// Number of value enhancements

Return ValueEnhancement.LastRowIndex + 1

End Function

Public Function RowData(table as iOSTable, section As Integer, row As Integer) as iOSTableCellData
// Populate a specific cell

Dim cell As iOSTableCellData = table.CreateCell

cell.Text = ValueEnhancement(row)

cell.AccessoryType = iOSTableCellData.AccessoryTypes.None

Return cell
End Function

Perhaps I wasn’t clear in my original post…

As per the documentation, iOSTableDataSource.RowData is called when the table wants “actual cell data for the section and row”.

In my experience, this means that it’s called when iOS is about to display a particular cell. So, for example, in a data source that contains 10,000 items, it’s only called ~15 times when the table is initially displayed because that’s the number of visible cells.

I understand that if iOSTable.EstimatedRowHeight isn’t set for the table then it can be called more times because the table needs to work out how long it is, so I’ve set iOSTable.EstimatedRowHeight for this table to avoid that.

What I’m seeing is inconsistent behaviour between the initial loading of a view containing a table and subsequent reloads of that table.

For the first load when pushing to the view containing the table, iOSTableDataSource.RowData is being called for every row in the data source. For subsequent loads, it’s only called for the initially displayed rows. So, in my example of a 10,000 row data source, the first load calls iOSTableDataSource.RowData 10,000 times and then reloading the same data set causes it to be called just 15 times. This causes a delay before the view is shown.

I’ve found a workaround: I can make the initial load when pushing to the view containing the table use a data source with no rows to make the initial display of the view instant, then use Xojo.Core.Timer.CallLater to trigger a reload of the data source. This is fast, but feels like a dirty workaround.

So… why is Xojo calling iOSTableDataSource.RowData for every row during my initial load but only for displayed rows on subsequent reloads of the data source?

This is getting weirder.

My workaround (of doing a dummy empty data source load when pushing to the view containing the table and using Xojo.Core.Timer.CallLater to trigger a reload once the view is visible) is working most of the time on iPhone and when I insert a breakpoint on iPad, but is sometimes failing on iPhone and always on iPad without a breakpoint that pauses loading to bring up the debugger. It feels like a timing issue.

If anyone has any ideas as to why iOSTableDataSource.RowData is being called so much before the view is displayed then please fire away!