The title of your question, "What is the exact order of UITableViewDelegate methods", presumes there is a defined order. The methods you identify:
- numberOfSectionsInTableView:
- numberOfRowsInSection:
- cellForRowAt:
are in fact defined in the UITableViewDataSource protocol which makes no mention of the order in which the methods are called. There seems to be a "logical" order, which is broadly what you observe in your Case 1. However, there are exceptions to this: in my testing, numberOfSectionsInTableView:
gets called twice in succession, without the other methods being called in between.
In your Case 2 you specify a huge number of rows, and the tableView therefore throws an exception. This seems understandable: the tableView is unable to "allocate data stores" for all those rows. If it is storing even 1 bit of information for each row, that's 46 Terabytes. Not really surprising it throws an exception.
Your Case 3 is obviously middle ground. Why no immediate exception? Who knows. The space requirement would be 468 Gigabytes, so far more than any current device, but within the bounds of credibility for a few years hence. Given that iOS runs on numerous different devices with different memory sizes, some 32bit, some 64bit, etc, the Apple Developers can't, for any given number of rows, be "sure it's gonna crash". So plainly they've decided/defaulted to trying.
So what is happening after calling numberOfRowsInSection
and before calling cellForRowAt
(or crashing)? The tableView is obviously doing something to try to fulfil the request for those rows.
The UITableViewDelegate protocol defines several methods under the heading "Configuring Rows for the Table View":
- heightForRowAt:
- estimatedHeightForRowAt:
- indentationLevelForRowAt:
- willDisplay:forRowAt:
- shouldSpringLoadRowAt:with:
These are all optional methods, but implementing them might give some clue as to what's going on. From what I can see, heightForRowAt
is called after cellForRowAt
(so only when a cell has been allocated to a particular row). But it looks like estimatedHeightForRowAt
is called separately for each and every row, after numberOfRowsInSection
and before cellForRowAt
.
Why should the tableView want to know the estimated height of all the rows, before loading a cell for even one of them? My guess is that the tableView is trying to determine its overall contentSize
: adding up the heights of all the rows to get the total height. Implementing estimatedHeightForRowAt
is obviously adding to the tableView's work and so slowing it down, but even if you have not implemented that method, the tableView must be doing something to calculate the height of each and every row: that takes time and memory.
Turning to your conclusion, "the concept 'Only cells that is to be displayed in screen will be loaded for tableview' is failing": note that the memory being used and the time taken is related to the number of rows, NOT the number of cells. The method names all refer to ...*row*At
. Even the exception in Case 2 refers to the data stores for rows. If you log cellForRowAt
you will see that it is called only for as many rows as are on screen, give or take a couple, until you scroll. Scrolling causes cells to go off screen, at which point the tableView puts them in its queue ready to be reused ("dequeued") for a row about to appear on screen. So your conclusion is wrong: cells are only loaded for rows appearing on screen.