UITableViewCell is frozen (not rerendering with new data). How to fix? - iphone

Having some issues with a tableViewCell freezing. I have a table view cell with a list of exercises. When I add a new exercise on another viewController, then pop back to this tableViewController that lists all the exercises, the respective cell gets frozen (see screenshot). Then, if I call [self.tableCell reloadData], that cell never refreshes.
it's weird because if the offending cell is, say, index #4, and I change the data source to only have 2 items, the 4th cell is still frozen. (the first 2 render correctly, the 3rd is blank, 4th is offending cell)
List of all exercises:
When I change the data in the tableView data source, that cell is still frozen:
If I put a breakpoint and inspect the tableView, it doesn't say anything about that frozen cell:
Not sure where to go from here :( It seems to only happen when I insert a row from a different viewController then pop back to this one.
Any thoughts? Thanks so much for any help!

You are keeping a reference to a cell. That is a bad idea. It contradicts the whole pattern of datasource and recycling of table cells. All kinds of wacky bugs will be the inevitable result.
Instead, you should make sure your datasource methods return the correct number of sections and rows, and the appropriate cells and then reload your table not a cell.
[self.tableView reloadData];
So, for example, when the view is returning from adding a new item, make sure the data array you are using is updated and reload.

I exactly don't understand your way of managing tableview along with data source. If you make any change in data source, same changes should be reflected in tableview as well. (Both should be synchronized). You can use:
Table reloadRowsAtIndexPaths:
Table deleteRowsAtIndexPaths:
Table insertRowsAtIndexPaths:
to make changes to your tableview and its cells. Or you can just call [Table reloadData]
Remember: never try to store references of UITableViewCells as they are dequeued again on screen - your reference will be just a trash. Just alter your cells using above 3 methods and you are good to go. If you want to clear something, just ask for it.

Related

Update table cell on notification

How can I update a tabelview cell when a particular notification received, without reloading table data. notification tells the id of the cell that I need to update. So I want to iterate all table cells and update only the relevant table cell without reloading it. how can i do this
Use [tableView visibleCells] to get a list of all cells that are displayed. Iterate through this array to see if the cell you need to update is displayed, then do whatever you need to. (this method is if you're reusing cells).
You can just use the built in reloadRowsAtIndexPaths:withRowAnimation: instead of trying to usurp the framework's functions. This will efficiently only reload the cell you ask it two not the entire table or even an entire section.
Reloads the specified rows using a certain animation effect.
Reloading a row causes the table view to ask its data source for a new cell for that row. The table animates that new cell in as it
animates the old row out. Call this method if you want to alert the
user that the value of a cell is changing. If, however, notifying the
user is not important—that is, you just want to change the value that
a cell is displaying—you can get the cell for a particular row and set
its new value.
When this method is called in an animation block defined by the beginUpdates and endUpdates methods, it behaves similarly to
deleteRowsAtIndexPaths:withRowAnimation:. The indexes that UITableView
passes to the method are specified in the state of the table view
prior to any updates. This happens regardless of ordering of the
insertion, deletion, and reloading method calls within the animation
block.
Available in iOS 3.0 and later.

Editing controls disappear on reload

Having a bit of trouble.
I've got a UITableView in grouped mode. The table is set to always be in editing mode - which is working just fine. All my rows are delete-able. The rows are indented and all of my UITableViewCellEditControls show up great.
Problem is when a row actually gets deleted I update my data source and then call:
deleteRowsAtIndexPaths:
reloadRowsAtIndexPaths: //needs to get called because of table aesthetics
After the reload occurs (I've tried just a simple reloadData, too) all of my UITableViewCellEditControls (the red circles with the minus signs etc) disappear! The rows are still indented, but they're gone.
I've tried the suggestion on this post:
UITableViewController canceling Edit mode animation when calling [table reloadData] inside (void)setEditing
But no luck.
Any help would be REALLY appreciated!
Without looking at any code, I have some suggestions.
According to Apple's UITableView Class Reference: under ReloadData, it says:
Call this method to reload all the data that is used to construct the table, including cells, section headers and footers, index arrays, and so on. For efficiency, the table view redisplays only those rows that are visible. It adjusts offsets if the table shrinks as a result of the reload. The table view's delegate or data source calls this method when it wants the table view to completely reload its data. It should not be called in the methods that insert or delete rows, especially within an animation block implemented with calls to beginUpdates and endUpdates
Blockquote
it shouldn't be called when inserting and deleting rows.
From what it seems like, you are allowing them to delete individual cells, therefore, I am assuming the following methods are already implemented: tableView:editingStyleForRowAtIndexPath: and tableView:commitEditingStyle:forRowAtIndexPath: In your commitEditingStyle, you should be just calling the delete method with something like this:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
This should remove the need for any reload data. If you don't want to show any animation, you can just use noanimation enumerator instead of the fade I showed in example.
If however, you still think you need to do reload data after every cell deletion, maybe try it with performSelector:afterDelay:
Hopefully, this tid-bit helps!

Calling cellForRowAtIndexPath through an instance

I was wondering if the following scenario is possible.
I have a UITableViewController class which contains ten rows displaying some data. Now, I want to show the first five rows in one tableview and the last five in another. Since I don't want to fetch the data again I was hoping to create an instance of my original table class and call its cellForRowAtIndexPath:(NSIndexPath*)indexPath to return the table cells and add it to the other two table views. Is it possible to call a delegate method through an instance? If so, how can I create an NSIndexPath object pointing to a particular row in any section of the table...
Thanks for the replies. I tried calling the cellForRowAtIndexPath:(NSIndexPath*)indexPath but it always shows the following warning
'RootViewController' may not respond to '-cellForRowAtIndexPath:'
Also the application crashes with the message
***Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[RootViewController cellForRowAtIndexPath:]: unrecognized selector sent to instance 0x4bad30'
Had initialized NSIndexPath as Andrei described.
Guess its just not possible to call the function.
If you don't want to fetch again, why don't you just add your fetch results to an array?
This would have the advantage that populating your tableview would not require "live fetching" - fetching data as you need it may in some cases make scrolling a tableview slow or stuttering may occur.
However, you could also try to add your tableviewcells to one or more arrays to keep references to them while you pupulate your tableview for the first time.
I don't think you need anything that elaborate.
Have all tables using the same datasource. Choose which items to display in which table based on the tag value for that table element. Call reloadData on all tables when anything changes.
My guess is that using the same UITableViewCell in 2 or more tables would not work.
If you are reusing cells then it's very likely that those duplicated cells will eventually be refreshed with another content.
To protect against this, you would need to clone those cells, in which case it's not feasible to work on a UITableViewCell level.
You're better off storing the data (displayed by the cells) in a array (or other storing way) and share that data across multiple tables.
Plus, you'd have the extra ability to customize the appearance of those tables independently while sharing the same content.
To answer your last question, you can create a NSIndexPath to point to any cell.
The first index is the sectio, and the second index is the row in that section.
For example, to point to section 2, cell 5 you can write something like this:
NSIndexPath* myIndexPath = [[NSIndexPath indexPathWithIndex:2] indexPathByAddingIndex:5];
//Or, with another method:
NSIndexPath* myIndexPath = [NSIndexPath indexPathWithIndexes:indexes_array length:count];
Remember that cellForRowAtIndexPath: is not a method of UITableViewController. It is a method of UITableView. With this in mind you would actually call the method like so:
UITableViewCell *cell;
cell = [yourTableView cellForRowAtIndexPath: indexPath];
Doing so should return the cell at indexPath.

Cell Dequeue problem when table inside another table's cell content view

I am using two table views (Main Table and Sub Table), one table inside other's cell.
I am adding Sub Table in Main Table's cell content view.
I am also using different Cell Identifier for both table cells.
Now, issue is :
When - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
is called,
very first time cell of Main Table is generated and when I scroll up/down they all are just dequeued, so it is expected and standard behavior and working fine.
But, cell of Sub Table is getting created/allocated every time. It is not dequeued as it should be.
I guess, its happening because Sub Table is part of Main Table's Cell Content view. But not sure and don't know how to resolve it.
Can somebody help me to find the solution?
You'r problem is exactly as you described it: The sub table UITableView object gets deallocated completely, and its cell queue along with it. You could try retaining the sub table views for each main table cell separately in an array or something, but this is ugly and prone to retain mess. Table views weren't designed for the way you are using them. In one project we faced the same design, we ended up drawing the sub tables as general views, with simple subviews in a for cycle for the sub table cells.
It's up to you to decide if you can go on the way you started or to change implementation to a different approach, but if you don't need scrolling and cell-reusing inside the main table cells I recommend you abandon the sub table being a UITableView approach completely.
I had the exact same problem. It is because the example tutorial uses deque, I just changed it for the pointer to go to the cell instead of deque.
cellForRowAtIndexPath:indexPath
Worked for me.

Is it possible to preload all the cells in a uitableview?

Is there a simple way to preload all the cells in a uitableview?
I need to do this in order to change whether or not all the cells are checked. If I just use cellForRowAtIndexPath, and the user say unchecks all the cells, and then checks a visible cell and starts to scroll again, either the selected cell gets deselected or the newly loading cells are selected.
It seems the easiest way to go would be to preload all the cells if possible.
Thanks!
Don't use the cells as your database.
Your cells are just a narrow window onto your data. The cells just show you a few of the objects in the underlying data. If you try to preload all the cells so you could then select them all, the UITableView could die a slow death, or slow crawl. Especially if we're talking hundreds of entries.
If you want to select all the items in your data, you do so with a direct call to your data to select its objects. Then, you reload the data into your TableView with a reloadData and if everything is set up right, your cells will show the selected state.
Read up on UITableView. Look at Apple's samples. You need to see the separation of data from the view and the controller.
Please re-read the answer I wrote here to your previous, similar question, which explains one solution to your problem.
Again, you should consider keeping an array of on/off settings. You can use NSMutableArray or a C array of int or BOOL values, whatever you want. But it definitely sounds like you need a data model.
Your -tableView:cellForRowAtIndexPath: looks up values of this array. Each value in the array corresponds in some way to a row in the table.
If you only have one section, then you can simply use the ith element of the array to set the checked state of the ith row of the table view. If you use NSMutableArray to store NSNumbers, you can handle resizing quite easily.
If you have more than one section, keep an array of arrays. Each top-level array corresponds to a section. Each inner array corresponds to a section's rows.
If you use NSMutableArray to store NSMutableArrays of NSNumbers, you can handle resizing and section addition and deletion quite easily.
The method -tableView:cellForRowAtIndexPath: then sets up cells with or without checkmarks, depending on the array's value.
Having a data model gives you the freedom to programmatically perform "select all" and "deselect all" button operations.
For example, when you click a button to "select all" cells:
Loop through the array and set each value to YES or 1 or whatever "on" label you chose originally.
Call [tableView reloadData], which is a method that goes back to -tableView:cellForRowAtIndexPath: and which will set a cell's checkmark state based on the state of values in the updated array.
No, you can't do this. You seem to be under the impression that a cell represents a particular piece of data, it doesn't. When the top cell scrolls off the screen it is usually recycled and brought in as the bottom cell. So a list that has hundreds of items you can scolled through may only ever have 8 or 9 cells alloc'ed and initialized.
You need to rethink your application's architecture. When you "uncheck all" it shouldn't change the visual state of the cell, it should change some state in the objects the cell represents, then when you load the cell for the object at that index path you should read that state and set the check mark appropriately.
The changes in the visual state of your cell should always be in response to changes in your underlying model.