Manually recycle UITableViewCell - ios

Is there an opposite method to dequeueReusableCell? I am dequeuing cells for cell height computation and after it computes its height I want to recycle that cell so it can be reused for display.
Or should I just instantiate an object per cell type, store it in a property, and the use those instead?

You could create your own stack / queue, and then put all cells that you dequeue manually (e.g. outside of cellForRow..) into this queue.
Inside of the cellForRow... method, you would then first use the table views dequeue-method, and if this returns nil, you would use your own queue to retrieve reusable cells. Only if none of them returns something, you then would create new cells.
But remember the the table view's dequeue-method only returns cells that you already have created before in cellForRow!

This is still not possible in iOS 10. I will update the answer if this is available in the future.

Related

iOS: UICollectionView content reset and dequeueReusableCell

Okay the situation goes as follows:
I have a collection view where in cellForRow I am using dequeueReusableCell to reuse the cells. On each cell I have a custom UIView object that is added as a subview.
Now, under a certain circumstance I must re-layout the collection view entirely. When this happens
Clear all item from data model
Call deleteItems for all visible cells' index paths
Call reloadData
At this point the collection view is empty and there are no cells displayed.
Now if I update my model again with data and reload the collection view - In cellForRow dequeueReusableCell returns reused cells/the added UIView as explained above is there!/- it does not initialize new cell objects even though the collection view was empty before the current update. I am not sure if this is the expected behaviour or I have some other problem in my code, however my question is - how can get to a point where I reset all the content on the collection view and dequeueReusableCell returns a newly initialized cell object.
I have learnt this the hard way! Save yourself some time Petar by knowing this that In any collection view/tableview, anytime there is any change of constraint or any UI element in its layout structure, you should ALWAYS, and ALWAYS make another prototype cell. It is the ONLY correct way, so don't think you ll be putting some more time in making another cell.
As I read your comment where you said you ll initiliaze another view based on that one condition where you want to reset everything. Just have another cell prototype with that another view and dequeue that now.
Hope it solves your problem

Reusable identifier cells versus returning a cell subclass?

I create my table view cells in xib files that I then register with my table view and return in cellForRowAt using the tableView.dequeueReusableCell method. In the rare instance I create cells by subclassing them and manually programming the interface I usually just initialise them and return them from within cellForRowAt.
I recently discovered that you can register subclasses using tableView.register(cellClass: AnyClass?, forCellReuseIdentifier: String). Should I be registering my subclasses and returning them via dequeueReusableCell? What are the benefits of using it instead of returning an initialised subclass?
You have to always register cell(via code or in storyboard). The Reusability principle is the most important in iOS Table and Collection views.
It means that the table view draws and stores in the memory only few cells that are currently visible + several that mat be visible in the nearest future. If you will not use reusability you will have a big performance problems with big amount of cells.
Also don't forget to clean cells ui in prepareForReuse method in cell subclasses
Yes, you should be taking advantage of the cell reuse system. The reuse system allows the system to very rapidly respond to scroll actions on your table. Instead of having to instantiate a whole new cell from scratch the system can just take cells it already has and update their content.
Bypassing that system by making a whole new cell every time is not an ideal use of resources and with more complex cells can result in noticeable lag on your table view.

Setting Content on 3 Separate Static TableViewCells that are of the same type

I have a tableview where a single prototype cell is used only 3 times. This cell has some buttons on it that trigger displaying and hiding content within the cell.
I could reuse the cells, but that requires a lot of resetting each cell so that if I expand A's content, B's content isn't expanded when it loads. Furthermore, this requires me to keep a state record in the Controller class, where I would prefer to have this all handled by the Cell itself for modularity. In other words, the amount of work to keep each cell in the correct stage seems inefficient.
What would be the best way to go about this? Do I use static cells? Is there a way to instance 3 separate cells of the same type and place them in the TableView?
You certainly can have the modular part of the code you need inside the cell itself. If you don't want to reuse the cells, then add a custom initializer with a case for each cell type. Inside your delegate method cellForRow:
return CustomCell(type: .myCustomType)
If you do it this way, you can add a switch inside the cell's initializer & set up the cells according to their types that way. And i'm assuming by "static" you mean just three instances. You "add" cells to the table by telling the delegate the number of cells that it will need, which will in turn call cellForRow x times.

How to update the heightForRow from UITableViewCell

The way my current design works is I dequeue a cell and give it a story id. In the cell initWithStyle I create mysubView (UILabel), set the autolayout constraints and fire a API request that loads the story title async. Then I set the text for the UILabel.
The problem is - at this point the UITableViewController already calculated the wrong height for the cell because initially the UILabel has no text. The only way how to update it now is by doing
parentTableView.beginUpdates
parentTableView.endUpdates
But it feels wrong because I need to reference the parent UITableView from within the cell and there has to be a better way. Am I missing something? I'm using UITableViewAutomaticDimension by the way for the row height.
I suggest you watch Session 211 of WWDC 2012, Building Concurrent User Interfaces and apply the concepts there. This features cells whose contents are independently queried and rendered.
The basic concept is as follows:
1. In tableView:cellForRowAtIndexPath, a cell is instantiated.
2. In the same method, an operation for retrieving the data to populate the cell is created and stored into a dictionary. A reference to the cell is passed to the operation. The operation has a completion handler that populates the cell and removes the operation from the dictionary.
3. Before the cell is returned from the method, the operation is added to an operation queue.
4. In tableView:didEndDisplayingCell:forRowAtIndexPath, operations for cells that have moved off-screen are cancelled and removed from the dictionary.
add following code in "cellForRowAtIndexPath" method before return cell.
cell.setNeedsUpdateConstraints()
cell.updateConstraintsIfNeeded()
also You can use only "updateConstraintsIfneeded"

configure UICollectionView cell on initial lookup

I am getting cells for a UICollectionView by calling dequeueReusableCellWithReuseIdentifier:. I want to set some specific configuration information the first time my cell is returned from this method and not subsequently when it gets reused. Is there a hook somewhere where I can run "one time" code on collection view cells?
Obviously I could just set this information every time or use a boolean to keep track of whether or not the cell has been initialized, but I'd like to know if there's a cleaner way first.
This is easy enough to do from within a cell's implementation but there's no convenient way for a data source to differentiate newly created vs reused cells. If your configuration must be supplied by the data source then the data source probably need to check if the cell has been configured already.
The cells will be created once so you can use init or awakeFromNib to set some initial state. Cells will then have prepareForReuse called when being reused allowing you to perform any changes you need to make per-use.
The way I ended up solving this was to put my own view inside a generic UICollectionViewCell with a view tag. Then, when I go to deque my cell, I pull out the view using viewWithTag. If I get nil back, it's the first time this code has run, so I can init my view using my own constructor normally. This seemed slightly better than keeping track of a boolean in the cell implementation.

Resources