ios/objective-c: changeUpdate and configureCell vs cellForRowAtIndexPath with NSFRC - ios

For a tableviewcontroller I use cellforrowatindexpath to configure the cell.
However, when changing something in core data, the delegate method controllerDidChangeObjectatObjectAtIndexPath fires and for the case changeUpdate, Apple seems to require that you rewrite the row with configureCell.
Is it best practice/necessary to entirely duplicate the code for cellforRowAtIndexPath in configureCell or is there a better way to keep the code identical. For example, would there be a way to do away with one or the other code blocks.
It seems error prone and redundant to have to have the same code for configuring the cell in both cellforrowatindexpath and configure cell.

Put the common code in another method and then call this new method from cellForRowAtIndexPath and configureCell. Or simply call configureCell from cellForRowAtIndexPath if appropriate.
Do not duplicate code. Refactor common code into a method that can be called from the places you would have had the duplicate code.

Related

Moving code to willDisplayCell to improve UITableview scrolling

I have seen this paragraph below from the internet and followed his recommendation and moved my code to willDisplayCell. However, I don't see any performance improvement. So I did some further investigation and found out that there are some other people saying what the paragraph said is not true. Proper Use of CellForRowAtIndexPath and WillDisplayCell . I am confused which guide I should follow at this stage as most of the time I put my code in cellForRowAtIndexPath
But very important thing is still there: tableView:cellForRowAtIndexPath: method, which should be implemented in the dataSource of UITableView, called for each cell and should work fast. So you must return reused cell instance as quickly as possible.
Don’t perform data binding at this point, because there’s no cell on screen yet. For this you can use tableView:willDisplayCell:forRowAtIndexPath: method which can be implemented in the delegate of UITableView. The method called exactly before showing cell in UITableView’s bounds.
I have done some test myself as well and found that there is no significant difference between putting the code in willDisplayCell and CellForRowAtIndexPath. So I believe the argument in the ink you have provided is more true. Unless anyone found anything different?

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.

Table cells not deleting properly from tableView swift

I am using a function other than apple's provided methods (canEditRowAtIndexPath and commitEditingStyle) to delete cells from a tableView. This is my code:
func deleteItem() {
items.removeAtIndex(currentIndexPath!.row)
tableView.deleteRowsAtIndexPaths([currentIndexPath!], withRowAnimation: .Automatic)
}
it does everything which generally occurs when deleting the rows. However, when new rows are inserted into the tableView, they layer the data from one of the previously deleted cells on top of the new ones, in this way:
The items can be added easily,
They can be deleted easily as well,
but when you try to add more cells, it has a problem:
At the moment, my best guess is that it has a problem with deletion of cells. any advice would be greatly appreciated.
At the moment, my best guess is that it has a problem with deletion of cells. any advice would be greatly appreciated.
If you can confirm for sure that your delete method is being called, by either using the debugger or a print statement, then I would say that your cells contain stale data from being dequeued, this would align with the laying you are seeing.
How do we confirm this?
Check your logic for your 'Add New Item' functionality.
Check your data source and make sure that it contains the correct data and number of items, you could check this in your custom delete method.
Set a breakpoint in the UITableViewDatasourceDelegate method below and inspect your cell's properties or use print statements to investigate. I would suggest cell.titleLabel!.text either way since that is the data you are seeing repeated.
tableView(_ tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath)
Try reloading the data immediately after a delete with the reloadData() method for UITableView.
See the UITableView reference document.
Discussion For performance reasons, a table view’s data source should generally reuse UITableViewCell objects when it assigns cells
to rows in its tableView:cellForRowAtIndexPath: method. A table view
maintains a queue or list of UITableViewCell objects that the data
source has marked for reuse. Call this method from your data source
object when asked to provide a new cell for the table view. This
method dequeues an existing cell if one is available or creates a new
one using the class or nib file you previously registered. If no cell
is available for reuse and you did not register a class or nib file,
this method returns nil.
If you registered a class for the specified identifier and a new cell
must be created, this method initializes the cell by calling its
initWithStyle:reuseIdentifier: method. For nib-based cells, this
method loads the cell object from the provided nib file. If an
existing cell was available for reuse, this method calls the cell’s
prepareForReuse method instead.
I just had this problem. You can't just have
self.tableView.deleteRows(at: [indexPath], with: .fade)
You have to remove it from your array too like this:
myArray.remove(at: indexPath.row)

Check if a UITableViewCell is selected, and the cell went off screen

I have a custom UITableViewCell that dequeueReusableCells. I have an int called selectedRow which gets the selected rows number in the method of didSelectRowAtIndexPath. I then pass selectedRow to an int called rowNumber which is in the class of my customCell.
In customCell.m, I have the method prepareForReuse. In that I made an NSLog of rowNumber.
What I want to do is: if a row is selected and that row went off screen, then perform some code. I would probably have to use prepareForReuse, but I don't know what to do in it.
I know it's a bit complicated, but if you have any questions, then I'd be happy to answer
Actually, you don't need to call prepareForReuse directly as it would be called automatically:
this method is invoked just before the object is returned from the
UITableView method dequeueReusableCellWithIdentifier:.
and as you don't know what to do in it, note:
For performance reasons, you should only reset attributes of the cell
that are not related to content, for example, alpha, editing, and
selection state
UITableViewCell Class Reference
You can use - (void)tableView:tableView didEndDisplayingCell:cell forRowAtIndexPath:indexPath; in UITableViewDelegate to know which cell is scrolled off screen.
However, this method is iOS6+ only.
You're over complicating things. You don't have to do prepareForReuse the in the custom cell.
Take a look at this.
http://www.icodeblog.com/2009/05/24/custom-uitableviewcell-using-interface-builder/
Its pretty similar for storyboards.

awakeFromNib is not called for UITableViewCell object

I have a class that inherits from UITableViewCell, it has a bunch of IBOutlets. I had previously been using this object in a way that reuses the cell and initializes it as it's needed. This method is too slow, so I decided to create an array of the UITableViewCell objects and then add them as needed in the cellForRowAtIndexPath: method.
Everything gets loaded fine except the IBOutlet objects. awakeFromNib is never called so I assume this has something to do with my issue.
Just to clarify it was getting called fine when I was initializing the cells in the cellForRowAtIndexPath function, it's just when I tried to preload them in the view controllers viewWillAppear method that it breaks.
I know this is an old question. But after reading the conversation, I feel I must give some input. This a multi-layered issue that you are dealing with here.
Firstly, when you say "preload" what is it that you mean exactly.? Are you calling dequeueReusableCellWithIdentifier in your viewWillAppear? Or are you calling an init. Either way this is not an acceptable practice whatsoever.
Remember, the UITableViewCells are "Reusable" meaning that the UITableView, in effect, handles the unloading and loading of the UITableViewCells when they are offscreen to optimize performance (not memory, believe it or not) as well as some other things. Essentially, it's a pretty nifty "hack" to keep table views efficient. So if your UITableView is too slow, then you are doing something wrong, not the implementation of UITableView
When you say you are "preloading" them, that throws up some immediate red flags on your usage. And when you say "the method is too slow", well it's not. The delegate/datasource methods in place for UITableViews and UICollectionViews happen in calculated orders. Don't fight it.
Secondly, for your issue with awakeFromNib not getting called. You aren't providing enough information. How did you initialize it? If you created it in your storyboard/nib, you shouldn't be calling any of the init methods. In fact, as of iOS6 you are guaranteed a non-nil cell from dequeueReusableCellWithIdentifier.
Have you called it through its super class like :
-(void)awakeFromNib
{
[super awakeFromNib]; // Use this line
}
Hope it helps you.

Resources