How to Clear cached UITableViewCells - iphone

So, I've been implementing Automated testing for my iOS app and I've come across a strange issue.
With the testing framework I'm using (Frank), it attempts to Touch views/buttons/everything based on Accessibility labels. This works great, except for with UITableViews because of how they cache and reuse UITableViewCells. If I "delete" a cell from the table, the table caching system will flip the cell to Hidden. But it will still be there waiting to be reused, and my framework can still see it, which is causing issues.
So, Question: How can I force a UITableView to release all deleted/cached cells so they will no longer be part of the View hierarchy?

This trick might help:
while([tableView dequeueReusableCellWithIdentifier:cellId]!=nil);
Of course, it needs manually repeat it for every possible cellId.
Note, cached cells is not a part of view hierarchy.
One more option. If UITableViewController is not currently visible, then invocation of didReceiveMemoryWarning method releases all its UITableViewCells.

In the method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath, use this:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]`
then check if your cell is nil. If it is, allocate a new instance of the cell.
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
[cell setDelegate:self];
}

Related

Disable uitableview disable reuse when scrolling in iOS

I want to disable reloading table view when scrolling. Now, my app when user scroll the uitableview, cellForRowAtIndexPath has been recalled.
Things in viewDidLoad
[listingTableView registerNib:[UINib nibWithNibName:#"TripCardCell" bundle:nil] forCellReuseIdentifier:[TripCardCell cellID]];
Things in cellForRowAtIndexPath
if (cell == nil) {
        cell = [[TripCardCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[TripCardCell cellID]];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }
UITableViewCell Class Reference
The reuse identifier is associated with a UITableViewCell object that
the table-view’s delegate creates with the intent to reuse it as the
basis (for performance reasons) for multiple rows of a table view. It
is assigned to the cell object in initWithFrame:reuseIdentifier: and
cannot be changed thereafter. A UITableView object maintains a queue
(or list) of the currently reusable cells, each with its own reuse
identifier, and makes them available to the delegate in the
dequeueReusableCellWithIdentifier: method.
Advantage of reuseIdentifiers
Using dequeueReusableCellWithIdentifier for the tableView, you can
greatly speed things up. Instead of instantiating a lot of cells, you
just instantiate as many as needed, i.e. as many that are visible
(this is handled automatically). If scrolling to an area in the list
where there are "cells" that haven't got their visual representation
yet, instead of instantiating new ones, you reuse already existing
ones.
disable reloading tableview when scrolling
You cannot block the cellForRowAtIndexPath: from calling when
scrolling the tableview. If something need not happen every time, You
may keep it in if condition.
if (cell == nil)
{
//Functionality goes here when it not needed to happen every time.
}

ios 5 prototype cells and VoiceOver issue

I am having a problem when trying to load a prototype cell when Voiceover is on. The app crashes and I get the errors
Assertion failure in -[UITableView _createPreparedCellForGlobalRow:withIndexPath:]
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
This only happens when VoiceOver is on, otherwise the app runs fine. Any help?
I'm not sure if I got this right by chance, but this worked out for me. In the UITableViewDataSource:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
[...]
UITableViewCell *standardCell;
if (UIAccessibilityIsVoiceOverRunning()) {
standardCell = [tableView dequeueReusableCellWithIdentifier:#"VO Cell"];
} else {
standardCell = [tableView dequeueReusableCellWithIdentifier:#"Regular Cell"];
}
//Configure the cell
[...]
return standardCell;
}
I believe it is the case that iOS caches Cells without the accessibility properties if VoiceOver is turned off for performance reasons. So the default Identifier you use may be related to a cached Cell that does not have these properties. When VoiceOver is turned on and iOS tries to dequeue these Cells, it does not find the properties in there and breaks. By having different Identifiers, you force iOS to cache new Cells when VO is on.
Again, this is only an assumption I'm making, but the case is that I do not get this issue when I dequeue Cells this way. However, if you do dequeue them the way I mentioned, you'd have to watch out for an error that may come along:
If you are dequeuing Cells whose Identifiers are set in a .xib file or in a Storyboard, like in the image below, you would then have to set another Prototype Cell with the VO Reuse Identifier.

Custom UITableViewCell woes

I have an iPhone app with a form input screen. I did this by making a custom UITableViewCell that has a UILabel and a UITextfield. I set it up so that the "cellForRowAtIndexPath" fetches the appropriate value from Core Data, and the UITextField's "textFieldDidEndEditing" method saves the appropriate value to Core Data. It works great... except:
If I edit a text field, then scroll it off screen, then click on another cell's text field:
The cell has been autoreleased because it scrolled off screen
The "textFieldDidEndEditing" gets a BAD ACCESS error
I understand the problem completely, I'm just not sure the best way to fix it. My first thought was to add the logic from "textFieldDidEndEditing" to "dealloc", but that seems hacky. Any suggestions?
I ended up using a delegate method for scroll view (which is built in to the UITableView). When the user starts dragging, I resign first responder.
This works perfectly because it looks nice, and "textFieldDidEndEditing" gets called when the user starts to scroll, which is always before the text field goes off screen.
disable scrolling while editing
retain your textField
that are the things you could do. In my opinion its best to disable scrolling while editing because the user has no need to, so make sure he also can not do so. Limit the things your user can do, makes it more "secure" for you and easier to use for the user.
If you are not sure about such things just look at what apple does, they are always right in their applications. Like in the settings app on iOS 5, when you change your phone's name. You simply get 1 row in the next tableview so you can't really mess anything up as the user..
In your custom cell's dealloc, set the textfield's delegate to nil
I had a similar issue... The problem lies in the reusable cells as part of the Table View. Every time the table is scrolled, the cellforRowatIndexPath gets called, and dequeues a cell and returns it. Sadly, this functionality doesnt work well with cells having retainable data such as labels. Hence you must opt for your own method of dequeueing the cell.
I have an NSMutableArray called cells which holds all my cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell *cell = [self dequeuwReusableCellwith:indexPath];
if (cell == nil)
{
cell = [[CustomTableViewCell alloc] init];
[cells addObject:cell];
}
// Configure the cell.
NSString *temp = [NSString stringWithFormat:#"Cell %d",indexPath.row];
cell.textField.placeholder=temp;
return cell;
}
and this is my custom method to deque Reusable cells.
-(CustomTableViewCell*)dequeuwReusableCellwith:(NSIndexPath*)indexpath
{
if([cells count]>indexpath.row)
{
return [cells objectAtIndex:indexpath.row];
}
return nil;
}
Hope this helps...

Creating UITableViewCell programmatically

I want to create a tableviewcell and add it on the view(not tableview) as
CGRect aframe=CGRectMake( 20, 20, 200, 200);
UITableViewCell *cell =[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.frame=aframe;
[self.view addSubview:cell];
But this is not working at all.
Can't we create cell independently and add to our view
UITableViewCell is meant to be used in a UITableView. I would imagine that there are things happening under the hood in UITableViewCell that assume that it's operating in a UITableView. Even if you were able to get this to work, I would expect it to be pretty fragile and vulnerable to breaking during OS updates, again, because it was written with the assumption of being embedded in a UITableView.

UITabBarController moreNavigationController table cell background images

Wow, was that ever a mouthful. :)
We've already seen a good thread on customizing the more menu (table view) in a tab bar.
For our next trick … how might one add a background image to the table cells?
I thought I could get away with overriding tableView:cellForRowAtIndexPath: in my More Table View's Data Source class (see earlier link for the methodology). Alas, it only changes the background under the image and accessory views to the left and right of each cell.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Let the original Data Source get a hold of the cell first.
UITableViewCell *cell = [originalDataSource tableView:tableView cellForRowAtIndexPath:indexPath];
// If we override the textColor, that works fine. (Commented out for now.)
//cell.textLabel.textColor = [UIColor whiteColor];
// If we override the background view … that doesn't work so well.
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cellBackground.png"]];
return cell;
}
I know, imageNamed: is evil, and perhaps I should create one background image and just reuse it throughout (vs. allocating multiple UIImageView objects). Apart from those items, any thoughts? (I tried adjusting the textLabel's backgroundColor too, to no avail … unless I'm doing something wrong there.)
Here is the answer...
Add the code in
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method of MoreTableViewDataSource
In addition to Sijo's answer post (thank you!), I just realized there was another thread on SO that takes a similar tack ... except I understand this code a bit more. However, I never cross-referenced it back to this question/thread! So here it is. See Ian1971's response in particular.