Alternative method for getting reference to a UITableviewCell? - ios

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.

Related

What is wrong if cellForItemAtIndexPath: is called in didSelectItemAtIndexPath:

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.

Why UICollectionView.cellForItemAtIndexPath always calls UICollectionViewDatasource.cellForItemAtIndexPath?

Scenario: I want to check selected state of specific visible UICollectionViewCells with indexPath for which I am calling cellForItemAtIndexPath on the UICollectionView reference.
Problem: Calling UICollectionView.cellForItemAtIndexPath always calls UICollectionViewDatasource.cellForItemAtIndexPath which returns a new cell without the selection state.
Question: Why UICollectionView.cellForItemAtIndexPath always calls UICollectionViewDatasource.cellForItemAtIndexPath ?
Apple documentation says the return value is "The cell object at the corresponding index path or nil if the cell is not visible or indexPath is out of range."
Am I missing something or is my implementation of cellForItemAtIndexPath in datasource incorrect ?
- (UICollectionViewCell*) collectionView: collView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
SudoCell *cell = [collView dequeueReusableCellWithReuseIdentifier:CELL_ID forIndexPath:indexPath];
[cell setValuesWithSection:indexPath.section item:indexPath.item modelObject:_model];
cell.backgroundColor = [UIColor whiteColor];
return cell;
}
As a work around currently I am setting storing the section and item values as instance values of the cell. Looping through all visible cells to find matching cells with the section and item values and checking visible state. This becomes tedious when number of cells are huge.
Please advice.
You're misunderstanding how protocols and delegates work. cellForItemAtIndexPath: is a delegate method that UICollectionView and UITableView call on its datasource in order to populate the Collection or Table View.
So lets say you have a CollectionView and you gave it a datasource. At some point when you run your application that CollectionView is going to call a method on the datasource numberOfSectionsInCollectionView: in order to get how many sections are needed for the CollectionView
Then it calls collectionView:numberOfItemsInSection in order to get the items for each section for the collection. This method is called for each individual section defined in the Collection View.
Finally it calls collectionView:cellForItemAtIndexPath: in order to get the Cells for each item of the collection. This method is called for each individual item defined in the Collection View. This would be where you could programmatically configure the cell to display the information you want, for instance, if you wanted to give the collection a Cell that had an image attached to it, this is where you would do it.
https://developer.apple.com/library/ios/documentation/uikit/reference/UICollectionViewDataSource_protocol/Reference/Reference.html
These are all datasource methods with the sole responsibility of providing data for the Collection View. If you want to respond to user interactions you need to use UICollectionViewDelegate Protocol and implement the methods
collectionView:didSelectItemAtIndexPath:
collectionView:didDeselectItemAtIndexPath:
As the signature implies, these methods are called in response to actions performed on the collection, along with an IndexPath describing the section and item number of the cell the action as performed on.
https://developer.apple.com/library/ios/documentation/uikit/reference/UICollectionViewDelegate_protocol/Reference/Reference.html
UICollectionDelegate Protocol reference above you can use to respond to different events that occur in that view
But none of that information above is any use to you if you don't have a basic understanding of protocols and delegates. I would recommend spending time reinforcing that understanding first before continuing

UISearchbar Static Tableview

Is it possible to have a UISearchBar on Static Cells, I really need the static cells, and there are like 40 of them, so how can I use the UISearchBar in it?
My Cells are filled with a button (Every name has another button (Every Cell has another name)).
So basically I need to search for the button text onto of each cell, and for that show the cells that contain the search string.
Can someone provide help please?
Thanks for your time and effort.
When you use static cells, as you probably already know, you don't implement the delegate methods in your UITableViewController. However, if you want to only display some of your static cells (or change the ones displayed), you can implement the delegate methods and call super on them after making whatever changes you need.
So by this I mean... If I have a static table view with 1 section, 3 cells, and I only want to display the first cell and the last cell, I would implement - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section, and have it return 2. Then I would implement - (UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath, and when it gets called with the index path with section 0, row 0, I'll call the superclass method with section 0 row 0. And when it gets called with section 0 row 1, I'll call the superclass with section 0 row 2. Basically, I'm mapping from indices of rows that will be displayed to the indices in the complete static table as defined in the storyboard.
However, I would suggest that you don't need to use static cells at all, and it will be a lot simpler. You won't have to deal with this mapping to make this work. You would maybe want to use static cells if your cells have UITextFields in them, or some other type of view that could cause problems for reuse. But in your case, a dynamic table would be much better to use because you don't have any content in a cell that would need to possibly be saved if a cell were going to be reused at a different index.
If you go the dynamic table route, you just need to implement the delegate for the search bar, and as you type you will store the list of filtered results in an array stored in an instance variable or property, and reload your table, using that array as the data source.

dequeueReusableCellWithIdentifier returns nil in didSelectRowAtIndexPath method

I'm using CustomTableCell in my project. I can see the "dequeueReusableCellWithIdentifier" is returning a valid cell in the method "cellForRowAtIndexPath" as it should eg whenever the table is reloaded.
In the CustomTableCell I have some images that I want to reuse, without downloading them again. However everytime i get a "nil" with the "dequeueReusableCellWithIdentifier" when used inside "didSelectRowAtIndexPath" delegate method.
The original table was not destroyed. The table is class object and I can see it is the same as the tableView received in the "didSelectRowAtIndexPath" parameter.
This behavior is consistent with out viewcontrollers in my project where I have used tableview.
I'm using ARC. Any idea what could be wrong ?
Thank you!
The question is a little vague, but I believe you're simply trying to access your custom cell from within "didSelectRowAtIndexPath". If this is the case, then you should utilize:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableCell *myCell = (CustomTableCell*)[tableView cellForRowAtIndexPath:indexPath];
}
Then you're free to access any part of your custom cell that you wish.
In case your curious:
"dequeueReusableCellWithIdentifier" is utilized to reduce the amount of object allocations & deallocations by reusing table cells that have "moved" beyond the visible range. i.e If you have a table with 1000 cells, but only 10 are visible at any given time. ~10 cells will be created and reused over and over again. Thus, when called dequeueReusableCellWithIdentifier will pull one of these cells off the stack of cells that aren't currently being utilized, or create one if the stack is empty.

iOS callback when uitableviewcell gets destroyed

As a user scrolls up and down in an uitableview cells get destroyed and created.
Is there a way to detect when a cell is going to be or has been destroyed?
Assuming that by "getting destroyed" you actually are referring to a cell getting reused, simply implement prepareForReuse within your UITableViewCell derived class.
prepareForReuse
Prepares a reusable cell for reuse by the table view's delegate.
- (void)prepareForReuse
Discussion
If a UITableViewCell object is reusable—that is, it has a reuse
identifier—this method is invoked just before the object is returned
from the UITableView method dequeueReusableCellWithIdentifier:. For
performance reasons, you should only reset attributes of the cell that
are not related to content, for example, alpha, editing, and selection
state. The table view's delegate in tableView:cellForRowAtIndexPath:
should always reset all content when reusing a cell. If the cell
object does not have an associated reuse identifier, this method is
not called. If you override this method, you must be sure to invoke
the superclass implementation.
Availability
Available in iOS 2.0 and later.
See Also
– initWithFrame:reuseIdentifier:
#property reuseIdentifier
Declared In
UITableViewCell.h
Without going into the implications of suitability or performance, another option might be to periodically check what cells remain visible, using the visibleCells method of the UITableView class:
- (NSArray *)visibleCells
As per the documentation:
Returns an array containing UITableViewCell objects, each representing a visible cell in the receiving table view.
You can subclass UITableViewCell and override it's dealloc method.
Any good reason to do it assuming you are reusing the cells to save the resources ?
What you're attempting to intercept is part of the internal implementation of UITableView and how it manages its cells. While there are ways in which you can attempt to intercept such behavior, I would suggest that you avoid using them, as there is no guarantee that future implementations of UITableView will maintain this behavior.
It would be better in cases such as this to consider a different approach: be it design and implement your own table class, or change your code logic.
As stated above, cells aren't destroyed when the leave the screen. However there are some things you can do, to track related actions, depending on what you are trying to do.
First there is a delegate message:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
This is called before a cell enters the screen. Another possibility is the already stated prepareForReuse method of a cell.
Another approach would be: Try and override willMoveToSuperview: or any other of the related methods. I am not sure if this is fired after the cell becomes invisible, but it might work.
Best regards,
Michael

Resources