What is wrong if cellForItemAtIndexPath: is called in didSelectItemAtIndexPath: - ios

I called cellForItemAtIndexPath: in the didSelectItemAtIndexPath: method. The result was that didSelectItemAtIndexPath: was only called one time per cell. So I can tap the first time on a cell, then I can tap on another cell, but if I tap on the first cell again the didSelectItemAtIndexPath is not called anymore (but all other "new" cells).
Now I'm not calling cellForItemAtIndexPath: anymore and now didSelectItemAtIndexPath: works as expected. But why I'm not allowed to do this? Any reasons for this?

The collection view is caching instances of cells for you and you dequeue them when you create the cell at an index path. The collection view is making some assumptions about what's going on when you do this, so if you start making multiple requests for cells at the same index path strange things start to happen. Sometimes this results in visual issues, sometimes interaction issues.
If you want to get the cell at a specified index path you should ask the collection view directly instead of using your own delegate method, this will give you the existing cell on screen rather than a new cell.

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

In UITableView, what's the delegate for "visibleCells"?

When cells come in and out of device's screen, I want my viewController to know exactly what came and what went out. Is there a way to do this?
There isn't a delegate method just for "visible cells". There isn't anything called when a cell leaves the screen. There really isn't anything when a cell becomes visible.
There is the cellForRowAtIndexPath data source method. This is called when a cell is needed.
There is the willDisplayRowAtIndexPath delegate method. This is called when a cell will be displayed.
There is the didEndDisplayingCell delegate method. This is called when a cell is removed from the table view.
There is the indexPathsForVisibleRows method on UITableView. This lets you know what rows are currently in view.
There is the prepareForReuse method on UITableViewCell. This lets a cell reset itself to be reused for another row.
Better describe what you are trying to accomplish in order to get a more specific answer.

How detect when a cell is removed from a uitableview in iOS for this edge case?

I am able to detect when a cell is removed from the UITableView by writing a handler for the method tableView:didEndDisplayingCell:forRowAtIndexPath:. This method is called whenever a cell is removed from the display. However, there is one exception.
When the cell has a UITextField and the field is the first responder, this method is never called even when it's scrolled off the display and the cells immediately before it and after it are.
The cell is also confirmed to be removed from the UITableView with a test while the cell is scrolled off the screen. The call to cellForRowAtIndexPath: returns nil under this condition.
I also subclassed the UITableViewCell and wrote a handler for removeFromSuperView. Again this method is called for all the cells when the are scrolled off the screen except when the cell has a UITextField and it is the first responder.
Another thing to note is that the UITextField in the cell accepts key input while it is scrolled off the screen and the call to cellForRowAtIndexPath: returns nil. I can see this when the cell is scrolled back into view.
Does anyone have any solutions for detecting when the cell is scrolled out of view, so that the controller can get access to the UITextField?
You could try to resign your first responder manually before the cell disappears. Depending on your requirements, this could be done in multiple ways, usually when the user starts scrolling. You could restore the first responder after he finishes scrolling, if the cell is still visible. Probably better from the graphical design point of view as well.
Alternatively, you could try to implement delegate's tableView:willDisplayCell:forRowAtIndexPath: and make a previous visible cells set, which you'd intersect with tableview's visibleCells array. The elements that are not in the current visibleCells but are in the previous were removed. Then assign a copy of visibleCells to previousVisibleCells.
This is probably a bug in Apple's code, you could file a radar for it.

UICollectionView: Get indexPath of Cell that is not visible

I have a UICollectionView with several cells – there are always some of them outside the viewport, so there are cells being reused.
When an event occurs I want to take a specific cell and move it to the front of the UICollectionView. In order to make moveItemAtIndexPath() work I need to know the current indexPath of the Cell that I want to move.
When I initialize the Cells in the CollectionViewDelegate with the cellForItemAtIndexPath method I save its indexPath into a variable of the Object that is the model of the Cell (not it’s actual Object, just the model). Then I look at this variable when I want to move the cell.
This is working fine as long as the cell was visible once – it seems like it only initiated then, even though it is part of the CollectionViewData all the time.
How can I make sure my CollectionViewCell has an indexPath, even when it is not visible or has not been visible yet?
If you know what data (cell) you want to present at the front (I assume top) of your UICollectionView, why don't you just update your dataSource and reload your UICollectionView?

Alternative method for getting reference to a UITableviewCell?

The design of the app I am working on, specifically the tableview part is quite complicated.
There are around 5-6 methods in which I need to get a reference to particular cell from the table view.
What I do not like is that I have to use the
-tableview:cellForRowAtIndexPath
This is a datasource method and does a lot of heavy lifting. Custom cell configuration, dequeueing, getting data for particular cell..etc.. The point is all this code is executed again,even if it does not make any sense at all. The cell object is completely loaded already.
Am I right in my observation and if yes, is there a working tested and lightweight solution?
Perhaps there could be an index of references to all cells. Asking it, I would immediately get the reference without the datasource code.
UITableView has cellForRowAtIndexPath: method.
From UITableView reference:
Returns the table cell at the specified index path.
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
Parameters
indexPath The index path locating the row in the receiver.
Return Value An object representing a cell of the table or nil if the cell is not visible or indexPath is out of range.

Resources