I have a UITableView that collects data from a database. What I would like to know is if there is some way I can iterate in the UITableView collection and check the values of the cell? The reason I ask is because I would like to update each cell based on the current value that it has (change font, size, color, etc.). I've seen in another SO post regarding this topic, but since the cells are already created and their values are changed it is a bit harder for me. I was thinking of iterating through the UITableView before I call reloadData, but any other suggestions are welcome.
You should not iterate over the cells of UITableView, because some of them (in fact, most of them) may not be present until you request them. UITableView aggressively recycles its cells, so if a cell is not visible, it is very likely that you would be creating it from scratch only to put it back into recycle queue moments later.
Changing your model and calling reloadData the way your post suggests would be the right solution. iOS will ensure that it runs the update in a smallest number of CPU cycles possible, so you do not need to worry about the cells that are already created. This is also the easiest approach in terms of your coding effort.
A table view is for displaying data. The properties of your table cells should only be written to, not read from. The appropriate way of handling this situation would be to update your underlying model objects -- the objects that you use to populate the table view -- as the data changes, and then reload the affected rows.
The issue you'll encounter is that UITableView reuses table cells. Once a table cell scrolls off the screen, it's quite likely that the table view will reuse the same cell to display a different row.
This means it's fundamentally not possible to iterate over the table cells. When you need to refresh a row because its data has changed, you should call reloadRowsAtIndexPaths:withRowAnimation: (or reloadData if all rows have changed) and if the row is visible on screen, UITableView will call your data source methods and give you an opportunity to configure the cell for display.
Related
Hi I am tying to iterate through all the cells of my tableview but My tableview variable only let's me access the visible cells. so is there a way to declare the tableview without using the dequeuereusableCellWithIdentifier? or is there a way to iterate through all the cells?
Thanks,
To efficiently display a table, cells are used and reused depending on which ones are visible onscreen. In fact, this is what dequeuereusableCellWithIdentifier is suggesting - you specify different types of cells so they can be recycled later, as new ones are displayed and the components of offscreen ones are available for reuse.
You should define what needs to be changed or retrieve cells using table view cellForRowAtIndexPath.
You Are Already Accessing All The Cells In The TableView.
Note: I lied, two or more cells may be kept for quick reuse as well by tableView, but are not shown immediately.
At a time, a tableView only shows limited amount to cells to maintain performance and memory usage. So, for this purpose dequeuereusableCellWithIdentifier() method is utilised to let iOS handle the reuse of cells when necessary.
This way, no matter how large the dataSource, from 100,1000 to 1M, for the tableView, it will show the data in its cell smoothly and without any hiccups. That is why, you have limited cells visible and only those are the total cell used and reused by the tableView again and again.
By this definition, the total cell in use are the total visibleCells. So, when you are accessing the visibleCells, you are already accessing all the cells tableView has in use.
If you want to access all the data used by the cell, then please access the dataSource of tableView, not the visibleCells only.
Kind Regards,
Suman Adhikari
I want to access/update UITableView cell (using reusable cells) which is not in the current view . I know the table view cells are reusable, that can be the reason I am unable to fetch them but is there any way of virtually making and updating. OR I have to drop the reusable cell technique. Suppose tableview have total 20 cells but only say 7 are visible in the current view of iPhone. How will i update other 13 cells which are out of view bounds
Accessing and modifying cells (even if you could) would be a bad pattern. UITableViewCells are designed to be created and modified solely in the tableView:cellForRow:atIndexPath datasource method, where framework automatically asks you what to do with cells that are about to be displayed.
The whole idea behind reusability is that the system takes care of the view for you, and all you need to do is take care of your datasource and instruct the system, using the model, how to render cells, in its allocated datasource method.
This paradigm would be defeated if we started accessing cells manually and modifying them.
You can't access those cells because they are not added to the UITableView but are kept in a queue until user scrolls to them, then they are added to the UITableView. Instead update your model, which will reflect changes on the cells.
I want to loop through a TableView and extract the text from all the selected rows. I suppose I "could" create and maintain a special array that is updated every time a row is selected/deselected using the didSelect/didDeselectRowAtIndexPath methods. But creating a separate array seems like an extra step. Is there no way to let the TableView itself serve as the array and then simply loop through it and get the selected rows? What would the code look like? I'm new to Swift, so this might be a silly question.
Part of the problem is that cells are supposed to be reused, and when used this way it is not possible to loop through them all. You could get around this by using a unique reuse identifier for each cell, such as the indexPath itself or some underlying unique id in your model. Then, you could indeed loop through all cells and retrieve whatever state you desired from each.
You would, however, find your application crushed under the weight of too many cells being instantiated and kept in memory. If you don't have many cells you won't be killed, but try it with a big data set and your app will enjoy a very quick death.
It is far more efficient to store one array with a bunch of id's than a large number of memory-intensive UITableViewCells.
As mentioned in comments, you should work with underlying datasource, not the table itself.
For example if your table shows rows from Array, it is way more faster to retrieve strings directly from that array than creating UITableViewCells and get strings from them.
Get indices of selected rows using UITableView's property indexPathsForSelectedRows.
Query datasource for each row.
As has been said the tableview only handles displaying, your datasource is what powers the data shown if you think about it.
Plus as said before the tableview dequeues cells as they scroll on and off the screen.
The best way to achieve what you want is to add a property to your datasource for each element that will allow you to filter out the select properties easily.
How are you storing the state for each selected cell currently? As this is the same functionally you would use to be able to generate your selected text array.
I have to fill a TableView with lots of items (20.000 items frol sqlite) but I know that I will overload it.
Is there a way to load only the needed data when scolling ?
for example if I display 100 items when I scroll over 100 should I load 200 in the table or load only the items 101>200 ?
Also is it possible when returning the Cell content to fetch for EACH element in the embedded sqlite DB ?
Thanks
I have to fill a TableView with lots of items (20.000 items frol sqlite) but I know that I will overload it. Is there a way to load only the needed data when scrolling?
UITableView is designed specifically to load only the cells that are visible. You don't so much "fill" a table as you make the data available to the table via the table's data source. As the table scrolls, it asks its data source for additional cells, and it re-uses the cells that are no longer visible. This minimizes memory usage and maximizes speed. You don't need to do anything to achieve this other than implement the necessary table view data source and delegate methods in your view controller (or some other object).
Also is it possible when returning the Cell content to fetch for EACH element in the embedded sqlite DB ?
Sure, you can do that. Just implement your -tableView:cellForRowAtIndexPath: method to make the appropriate SQLite query for the requested cell.
This the default functionality of a UITableView, it only draws the necessary rows when they need to appear. This is why you have "reusable cells" because they keep getting reused. I think storing the 20,000 items should not be terrible memory overhead, so I would just try using the UITableView default functionality and you will be fine.
All,
I hope most of you know that with ios7 there is not need to do a null check for tableview reuse
if (cell == nil) {
But unfortunately, because of that the cells are always reinitialized, as we put the code in the same method for initializing values. The problem is only with text fields inside the tableview though.
Let me explain the scenario. I have a table view with multiple rows, and some rows contain multiple text boxes. I populate the textboxes with data from server when the page is loaded. Since the cells are always re-initialized as i explained above, whatever I enter in the field goes away and the server data is re populated once i scroll down and come back to the initial stage. This is because the populating the data code is also in the same place. After fetching a reusable cell it populates the data.
Previously till ios6, we used if(cell==nil) and hence we loaded server data inside the cell and when reusing the cell, this piece of code will never be called.
I have other dirty solutions, but would like to know if someone else has a graceful way of dealing this. Please help.
You just don't store any data in the table view cell but in the model that fills the table cell. This is always the way it should be done.
Looking from the MVC standpoint than the UITableViewCell is a view. Since it is reused by iOS you should use a model to the view.
Yes, this is the expected behavior of UITableView. For performance reasons, cells are reused. Thus, it is your responsibility to populate the views in a Table View Cell every time tableView:cellForRowAtIndexPath: is called.
The thing I don't understand from your question - are you making a network call every single time a cell comes into view? If so, cache the results somewhere. Or, if it's a small amount of data, consider just doing it all in one shot at the beginning (still need to be asynchronous though).
One thing I see a lot of developers do is move a lot of code into UITableViewCell subclasses, which sounds like a good idea because it's modular, but makes solutions for problems like this more difficult. Have the Table View Data Source manage the network calls.
If you need some inspiration, look at Apple's LazyTableImages sample.