I'm looking to call different methods based on whether the user taps a UITableView cell or it's selected programmatically. I can't seem to separate them, however; the programmatic one runs everything in the didSelectRowAt indexPath. Is there a way to use these more independently?
Here's my programmatic code:
func selectTableViewRowProgrammatically() {
let indexPath = IndexPath(row: someVar, section: 0);
self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableView.ScrollPosition.none)
self.tableView(self.tableView, didSelectRowAt: indexPath)
}
Thanks!
What do you want the app to do when you select the table cell manually vs. when you programmatically call it?
Currently your programmatically way calls the same method that is being called when you tap the cell, i.e. tableView(_:didSelectRowAt:).
So if you want to do any additional computations, just add it to your selectTableViewRowProgrammatically method before or after you call self.tableView(self.tableView, didSelectRowAt: indexPath).
To highlight a cell programmatically you can call selectRow(at:animated:scrollPosition:).
Note the Discussion part in the documentation:
Calling this method does not cause the delegate to receive a
tableView(:willSelectRowAt:) or tableView(:didSelectRowAt:) message,
nor does it send selectionDidChangeNotification notifications to
observers.
Related
I am calling the following function to update the tableView. However, I am finding that heightForHeaderInSection gets called twice for each section there are in the table. So if I have 5 sections, the function gets called 10 times. Is that normal?
tableView.beginUpdates()
let sections = NSIndexSet(index:posts.count - 1)
tableView.insertSections(sections, withRowAnimation: .None)
tableView.endUpdates()
To answer youre question lets look at UITableViewDelegate. From Apple documentation :
The delegate of a UITableView object must adopt the
UITableViewDelegate protocol. Optional methods of the protocol allow
the delegate to manage selections, configure section headings and
footers, help to delete and reorder cells, and perform other actions.
So when UITableViewDelegate is get called in your'e case? Delegate is get called when you update tableView with insertSections. So heightForHeaderInSection is called after you insert new sections to tableView.
Amount of times that heightForHeaderInSection is get called depends on how you update tableView.
Also it is possible to highlight that Apple do not gives clear explanation how often UIKit would call you're delegate methods.
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.
}
I am using storyboards for my app.In that I have a UITableViewController class.I am loading the UITableView from the data coming from the webservice. The issue is that the data is coming but is not geting populated in UITableView. On Decoding I found out that the cellForRowAtIndexPath method is not getting called.
Do we need to connect the datasource and delegate in storyboard as it was done in separate xibs before storyboard. And if so, where to connect the datasource and delegate methods as there is NO Filesowner in storyboard.
I am stuck up with this issue and any help would be appreciated.
Thanks
If you put a table view controller into a storyboard, it usually has the table view's dataSource and delegate already set up correctly. If yours turn out to be connected OK, the other possibility is that tableView:numberOfRowsInSection: is returning zero.
If you are using the UITableViewController, then you need to make the numberOfSections:tableView: data source method returns 1 instead of the default return of 0.
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1 // Default is 0, should be greater than 0
}
I am attempting to use a storyboard/segue to handle the transition between a UITableView with both standard transition as well as detail disclosure button. Having read a few different posts on here I have set up my project this way:
Tie main segue between UITableViewCell and ViewController
Tie secondary segue from parent ViewController to new ViewController
Implement accessoryButtonTappedForRowWithIndexPath as follows:
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"DetailSegue" sender:self];
}
This works great and my prepareForSegue: sender: gets called as expected. The trouble is, I need to know the indexPath for the element selected. The segue from the UITableViewCell retrieves the indexPath like this:
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
Unfortunately when I try to do that having called the accessoryButton, that returns null.
The original question I am basing some of this code off of is here: Detail Disclosure Button and Segues
Is there a method of the tableView which returns indexPath for accessoryButtons? Do I need to access the indexPath in some other manner?
You don't have to override accessoryButtonTappedForRowWithIndexPath.
In prepareForSegue, when working with a detail disclosure button, instead of:
[self.tableView indexPathForSelectedRow]
use:
[self.tableView indexPathForCell:sender]
The sender is already the detail disclosure button's cell.
The sender argument is, according to the documentation:
The object that you want to use to initiate the segue. This object is made available for informational purposes during the actual segue.
I don't see any reason why you can't use the index path as the sender instead of self, then access the index path in prepareForSegue:.
If that doesn't work, store the index path in an ivar and access that in prepareForSegue
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.