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.
}
Related
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];
}
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...
i have a uitableview in that i display data with the help of network queue . I use CellIdentifier like this,
NSString *CellIdentifier = [NSString stringWithFormat:#"%i_%i" , indexPath.section , indexPath.row];
and check condition
if(cell ==nil)
{
}
so data is loaded only one time .
by doing this, it loads data but the problem is in imageview. the image size is big so it takes some time. if image is not loaded and user scrolls the table then that image is never seen. To see the image we have to wait till it is loaded and then we scroll the table.
Is there any way to load the image again which are not loaded.
I dont want to load all data again .
You understood if(cell == nil) {} wrong.
This condition should not be used so your data is only loaded one time, this should be used to construct a new cell only when necessary.
You have to setup each cell outside of this condition.
And you should definitely not use a different CellIdentifier for each cell. This is a bad hack introduced by people who are to "lazy" to implement lazy loading of cell images correctly.
You should see the LazyTableImages example from apple to see how it should be done.
For loading images in table view, you can use good LazyTableImages Example by Apple. You don't have to write this type of code (different cell identifier for each). You have to reuse table view cell as per apple document otherwise it will take too much memory while scrolling.
I have a inherited UITableViewCell class from which I create a custom cell containing a UITextField.
The UITextField is 25 pixel height by default.
The behavior I want is that when the user clicks in the textField, the UITextField should change to 100 pixel height and the cell should grow accordingly.
I can detect when the UITextField receive focus thanks to notifications and observers but I wonder how to programmatically make that tableView:HeightForCellAtindexPath: be called.
Like Endemic says, tableView:heightForCellAtIndexPath: is the method you need to implement. According to Apple, the most efficient way to trigger a resize is an empty beginUpdates / endUpdates block, like this.
[tableView beginUpdates];
[tableView endUpdates];
It saves you the overhead of reloading the cell contents and, I believe, gives you a nice animation you wouldn't otherwise get from reloadData.
You must have a link between the cell and the table view controller. Since you are already creating your custom cell in your controller the easiest way would be to use the delegate pattern.
#class CustomTableViewCell;
#protocol CustomTableViewCellDelegate
- (void)customTableViewCellDidEnterTextMode:(CustomTableViewCell *)cell;
#end
#protocol (nonatomic, assign) id<CustomTableViewCellDelegate> delegate;
and just call the delegate method where you are detecting when the text field gets focus
[self.delegate customTableViewCellDidEnterTextMode:self];
and in the controller
- (void)customTableViewCellDidEnterTextMode:(CustomTableViewCell *)cell {
self.editingIndexPath = [self.tableView indexPathForCell:cell];
// from Jablair's answer
[tableView beginUpdates];
[tableView endUpdates];
}
And then in tableView:heightForCellAtIndexPath: just return your special height for self.editingIndexPath.
You would probably have to include another delegate method to know when focus is leaving the text field as well.
Another approach would be to use notifications but that will just complicate your code and if there is only one receiver of the message a delegate is the preferred way. A third approach would be to set the delegate of the text field to your controller instead of to your cell.
The bottom line, you need to provide the link between the cell and table view your self and I believe using a delegate pattern is the best approach.
The tableView:heightForCellAtIndexPath: method is called whenever the table view loads data, so simply calling reloadData (or one of the other, more selective reload methods) on the table view should work fine.
I understand that UITableView will call -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method to get each of the cells for the table view. Say I have my data source is fetched over the internet and I have to account for latency. What will be the best way of "stopping" this method from being called? Should it block on a boolean flag in the application? Should I just call cellForRowAtIndexPath again from within my application?
I am uncertain as to when the function gets called, ie, how often the UITableView "refreshes" itself. Any explanations will be helpful! Thanks!
If you don't have data, or you don't have the data for additional cells, then cellForRowAtIndex: will not be called as long as you don't tell the UTableView that you have rowCounts or new rowCounts. That value is being set in numberOfRowsInSection:.
In other words, don't report any new cells in numberOfRowsInSection:, until you actually have that data in hand, and then cellForRowAtIndexPath: won't be called prematurely.
When you do get the additional row data, then call reloadData to get the UITableView to ask for the number of rows and then call cellForRowAtIndex:.
If you've set UITableView datasource and delegate from IB then it will at least go for numberOfRowsInSection method when you push to the view, however if you're showing data from an NSArray, it'll return count ZERO if array is still empty, so table won't go for other methods to call.
In practice, I'm pulling data from web service to feed the table, so I am not setting up the datasource and delegate from IB instead once I get the data and status OK response I'd set the tableview.datasource = self and tableview.delegate = self and then call reloadData method to update table. This ensures that it won't go for numberOfRowsInSection method as you don't need to call it up without having the data.
What you should do is call reloadData on your table view when your data is done being fetched. That will force the table view to call it's delegate methods again for display. Those methods are called whenever the table view needs to re-display, so either when it comes into view, scrolling occurs, or you manually call reloadData.
When you invoke [tableView reloadData], the framework automatically invokes all the data source methods again for the table view cells that are visible currently (not for all the cells of the tableview). So the best approach would be to invoke reloadData every time you get data from the internet.