UICollectionViewCell reuse doesn't work properly - ios

I have cell of different width and horisontal UICollectionView, but often
when I dequeue cell:
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath)
it uses the same cell with the same object address.
Update:
I mean that UICollectionView uses the same cell for all IndexPath . In debug I see the address of the cell and it's the same all the time. But I think that it's the way, UICollectionView implemented, the bug was in another point, but anyway it's strange

Reusable cells come into picture when there are more cells than to fit the screen. You just have 2 fresh objects of cells with 2 indexPath rows that are visible on the screen.
Try checking the cellForItemAtIndexPath wherein you configure or modify the cell's data after you instantiate them, you would have given same data to show in both cells or you wouldn't have changed the default values for the cell's view's UI elements which my cause the data to repeat.

Related

Can I customize the reuse of UICollectionView?

I will create a carousel using UICollectionView.
And I want the cells outside the bounds of UICollectionView would be visible.
So I added this code because I thought it's an easy problem.
collectionView.isPagingEnabled = true
collectionView.clipsToBounds = false
But, Of course, some cells outside the bounds were hidden by reuse.
Is there anyway to use UICollectionView without reuse, or to adjust the reuse range, or ...etc?
Thanks in advance.
yes you can in fact use UICollectionView without reuse.
in collectionview's datasource function :
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
instead of using
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as! CollectionViewCell
and returning the cell, you can create your own cell without calling collectionView's dequeue function and return this newly created cell
the downside to this is everytime your collectionview need a new cell, it will creates a new cell and not reusing the one you already had, resulting in overtime increasing memory hogging cells
to solve this, you can arrange an array that keep track of which cell to use on which index, and fetch cell from this array (if its available) or create one when its not and append it to the array

Resizeable tableView cell with tableView inside it

I am creating a tableView with custom cells in which each cell can have different types of views ranging from key-value pair labels, map, buttons , list and more depending upon the data coming from the server and those views will be populated accordingly. I have created custom XIB for each view type which i will be using
So for this I took a parentTableView whose cell will have a childTableView whose each cell will be the different type of view depending on the data from the server
NOTE - Call and Navigation button and Assigned label are not cells but are added on top of the cell
Now I have two questions :
How can i make the childTableView to disable scrolling feature and take the full height of its content (In the image after last assignedTo, there is a priority field which is currently clipped as i have defined the height of the tableView cell to be 200 )
Dynamic height for parentTableView's cell (which is almost similar to first question)
I tried setting rowHeight and estimatedRowHeight for parentTableView but it is collapsing the cells
parentTableView.rowHeight = UITableViewAutomaticDimension
parentTableView.estimatedRowHeight = 300.0
remove parentTableView.rowHeight = UITableViewAutomaticDimension
and update your cell height to calculated cell.tableView.contentSize.height
ref:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = tableView.dequeueReusableCellWithIdentifier("identifier", forIndexPath: indexPath) as! CustomCell
return cell.tableView.contentSize.height
}

Proper way to identify static cells in Xcode?

I have a table view controller and I overrode this function:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
// Configure the cell...
return cell
}
My cell identifier is myCell. I created 4 static cells, and went into each cell and gave each the identifier myCell. However, this crashes due to not recognizing the cell identifier. However, if I change to dynamic prototypes, give the cell the myCell identifier, it works as intended. I guess this will do for now...as I can just tell it dynamically how many cells I want. But I'm really interested to find out why my static cells aren't working with the same exact method. Any ideas?
When you have static cells (i.e. a small, fixed set of static cells, rather than dynamic cells with cell prototypes where you control how many of which types of cells will be dynamically generated), you shouldn’t implement any of the UITableViewDataSource methods. Just create IBOutlet references for the various controls you have in your static cells and update them just like you would if you weren’t using a UITableView at all.
As an aside, if you were using dynamic cells, you would never give two different cell prototypes the same reuse identifier. The purpose of the reuse identifier is to let it know which cell prototype to use, and it wouldn’t therefore make any sense to give multiple cell prototypes the same identifier.

How can I stop the empty "ghost" cells in a table view from dynamically resizing alongside custom cells?

I'm using the typical method of dynamically sizing table view cells that contain text views in them:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44
This works just fine for the cells I actually instantiate and use, but it has a strange side effect: the empty cells that the table view shows below instantiated cells end up resizing their height alongside whichever custom cell I'm currently editing.
So when I input three, four, or more lines of text into a newly added custom cell...
...all the other prototype-based custom cells already filled in the
table remain unchanged
...the custom cell being edited resizes dynamically as intended
...but all the "ghost" cells below the last custom cell in the table
view end up dynamically expanding alongside the custom cell that's
being edited
My first thought was that it must have something to do with how I dequeue cells, and specifically what I return when dequeueing doesn't happen:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let myCell = tableView.dequeueReusableCell(withIdentifier: "myCustomCell", for: indexPath) as? CustomCell {
return myCell
} else {
return CustomCell()
}
}
But I tried returning both my custom cell and just UITableViewCell() in the else block and the result is the same.
Does anyone know why this could possibly be happening and/or how to get around it?

How to create tableview cells without using prototype cells?

In my tableview, every cell will be different and determined by a JSON response from server. And there will be infinite possibilities. So defining a prototype for each type of cell is not possible.
For example, one cell will have labels and buttons, another cell have images and buttons in different orders.
How to achieve this dynamic structure in tableview cells?
Currently what I am doing is: adding views as subview in cellForRowAtIndexPath but scrolling is very laggy this way.
How to achieve this without affecting performance this much
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! MyCell
for myview in data[indexPath.row].myviews{
cell.addSubview(myview)
}
return cell
}
If you're using a table view then your content is going to scroll vertically, right?
There is a physical limit to the amount of UI that you can put horizontally. Limited by the screen size.
So I'm guessing your UI parts are being laid out vertically in the cell?
So instead of laying out a button, label, image, another button, and a text field vertically in a cell...
Create a cell type called ButtonCell, LabelCell, ImageCell, MultiLineLabelCell, TextFieldCell, etc...
So now, instead of creating one cell with all these elements added. You instead create multiple cells each containing one type of UI. Now you can dequeue your cells in any particular order (driven by your JSON) and won't lose the performance.
The only solution I see is to have empty cell and add/remove subviews as needed. But you should add new subviews to a cell only if you did not add them before.
For example:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! MyCell
if cell.contentView.viewWithTag(1) == nil {
let label = UILabel()
label.tag = 1
cell.contentView.addSubview(label)
}
let label = cell.contentView.viewWithTag(1)
// label config there
return cell
}
Also don't forget to add subviews to cell's contentView not to cell itself.

Resources