I have implemented the code necessary to take advantage of reusable header views as described in the accepted answer here
UITableViewHeaderFooterView in InterfaceBuilder
To summarize, I have a NIB who's class derives from UITableViewHeaderFooterView, I register the NIB in viewDidLoad "forHeaderFooterViewReuseIdentifier" and I dequeueReusableHeaderFooterViewWithIdentifier in the "viewForHeaderInSection" method. This all works, compiles, and runs.
The code closely parallels the typical use/re-use of UITableViewCells also being used in this screen. If I set a breakpoint on the dealloc methods for both (the table cells, and table header cells) I see the table cells get created, re-used, and rarely dealloc'ed.
The call to dequeueReusableHeaderFooterViewWithIdentifier returns a non-nil value and the result gets returned as the viewForHeaderInSection. However, the header cell dealloc method gets called (for each header cell) every time reloadData is called on the table. The table cells don't, so in other words the header cells aren't really being reused, if the cell behavior is the standard for defining "re-use". Or, at least it can be said that the header cells aren't re-used as much as the cells are.
Apple provides an example of header reuse in the "Table View Animations and Gestures" code example. If I add a dealloc method to their custom header class, it DOES get called when table reloadData is called. (I added a timer to their class that calls reloadData every 10 seconds)
Does anyone know if this is the expected behavior and I'm misunderstanding "reuse", or has Apple not really implemented the reuse behavior for header cells that is seen in table cells?
Thanks
Related
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
I'm working on a view controller, where collection view cells are inserted when user scrolls.
I use reloadData() method only at the beginning. (viewDidLoad)
After first load, I use insertItems(at:) method whenever user scrolls.
There are a lot of cells to be added, so cells should be reusable.
But I'm wonder if cells are reused when I insert cell directly.
Are cells reused when they are inserted? (not reloadData)
Short answer: Yes, cells are reused.
Longer answer:
When you call dequeueReusableCell(withReuseIdentifier:for:) to get a cell for an item in the collection view it would return a reusable cell object located by its identifier.
Call this method from your data source object when asked to provide a
new cell for the collection view. This method dequeues an existing
cell if one is available or creates a new one based on the class or
nib file you previously registered.
Documentation
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.
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"
I have created a subclass of UITableViewController that is used as the custom class for a View in my storyboard. The view has a number of sections/rows defined as prototype cells which are instantiated and shown as expected. Most of the UITableView delegate methods simply call the super's methods that handle section amount, rows, etc.
I have cached content that is used to update the cells on -viewDidLoad and then an asynchronous operation that reloads the content from my server and rebinds the data afterwards (on the main thread, -performSelectorOnMainThread::). It is at this point that, seemingly arbitrarily, some of the cells content (labels primarily) will be cleared of data and not updated to the new data for anywhere between 10-15 seconds. At which point either the content which just show up or sometimes scrolling in the table view will cause the content to appear.
I know the selector is being called and on the main thread, the UI element's text properties are getting set but randomly they just...don't update. I've tried adding in -setNeedsDisplay on the tableView, controller's view and -reloadData on the tableView (though the last one seemed unnecessary as they're prototype cells) all to no avail.
Anyone come across this?
I am not sure if this is caused by the thread aspects, or how the tableView is handled. If it is tableView, check out this post since there are some similarity to disappearing data that my app was experiencing until I handled the dynamic, prototype tvCells correctly.
My comment did indeed fix my problem. It seems UILabel's are not updated when modified but rather it's decided internally when to repaint them - regardless if you try to force it with display or setNeedsDisplay.
Solution: Use a UITextView instead of a UILabel