Use didSelectRowAtIndexPath or prepareForSegue method for UITableView?
If you use prepareForSegue:sender:
then you won't have as much to change if you later decide to trigger the segue from some control outside the table view.
The prepareForSegue:sender:
message is sent to the current view controller, so I'd suggest something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Assume self.view is the table view
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
DetailObject *detail = [self detailForIndexPath:path];
[segue.destinationViewController setDetail:detail];
}
In Swift:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let path = self.tableView.indexPathForSelectedRow()!
segue.destinationViewController.detail = self.detailForIndexPath(path)
}
How can I run prepareForSegue After didSelectRowAtIndexPath?
If you have linked the segue directly from your cell in the storyboard then didSelectRowAtIndexPath
will not execute before the segue is triggered.
What you can do is create a segue by Ctrl-dragging from the view controller object in the storyboard to the destination scene and giving the segue an identifier as you would with any other segue. Delete the segue from your cell.
Now you can call performSegueWithIdentifier
to trigger the segue and pass the object that was selected as the sender
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// tableView.deselectRowAtIndexPath(indexPath) // Optionally deselect the row for a cleaner appearance
self.performSegueWithIdentifier("mySegueIdentifier", sender: queryArray[indexPath.row])
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let detailScene = segue.destinationViewController as? ListaTableViewController {
let categoriaEscolhida = sender as! PFObject
detailScene.categoria = categoriaEscolhida.objectForKey("nome") as! String
}
}
Swift didSelectRowAtIndexPath and prepareForSegue
You can fetch the selected indexPaths from tableView in your prepare for segue
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "editSegue")
{
if let indexPath = tableView.indexPathForSelectedRow{
let viewController : WorkoutView = segue.destinationViewController as! WorkoutView
viewController.workoutInfoData = marrStudentData.objectAtIndex(indexPath.row) as! WorkoutInfo
navigationItem.title = ""
}
}
}
Should I use didSelectRowAtIndexPath, prepareForSegue, or both?
Call prepareForSegue method inside didSelectRowAtIndexPath method to navigate to secondViewController then to display details, make network call inside viewDidLoad method of secondViewController and show activityIndicatorView until the data is fetched.
To Segue or to didSelectRowAtIndexPath?
You need to use both, in didSelectRowAtIndexPath
you should call [self performSegueWithIdentifier:@"identifier" sender:self];
In the same View Controller you should have the prepareForSegue
method grab the destinationViewController
out of the segue, and then set whatever properties on that view controller that you wish to set.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.someProperty = [self.someArray objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:@"segueID" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *vcToPushTo = segue.destinationViewController;
vcToPushTo.propertyToSet = self.someProperty;
}
Segue using didSelectRowAtIndexPath
You need to declare selectedNote as optional like this:
var selectedNote: Note?
And later check if value exist before using it.
if let note = selectedNote {
// Set up the detail view controller to show.
let detailViewController = DetailViewController()
detailViewController.detailDescriptionLabel = note.valueForKey("noteBody") as! UILabel
// Note: Should not be necessary but current iOS 8.0 bug requires it.
tableView.deselectRowAtIndexPath(tableView.indexPathForSelectedRow()!, animated: false)
// original code
navigationController?.pushViewController(detailViewController, animated: true)
}
Update:
The problem is that you are trying to create DetailViewController
let detailViewController = DetailViewController()
But what you need instead is to have reference to the DetailViewController in order to pass information to it.
So you can create segue from Master to Detail controller in Interface builder. Then remove logic from didSelectRowAtIndexPath
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Note: Should not be necessary but current iOS 8.0 bug requires it.
tableView.deselectRowAtIndexPath(tableView.indexPathForSelectedRow()!, animated: false)
}
And implement it in prepareForSegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let cell = sender as? UITableViewCell {
let indexPath = tableView.indexPathForCell(cell)!
var selectedNote: Note?
if filteredObjects?.count > 0 {
selectedNote = filteredObjects![indexPath.row]
}else {
selectedNote = self.fetchedResultsController.objectAtIndexPath(indexPath) as? Note // <--this is "everything"
}
if let note = selectedNote {
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = note
}
}
}
}
showDetail - segue identifier which you need to setup in IB.
var detailItem: AnyObject? - you need to declare it in DetailViewController.
in iOS app, why does prepareForSegue occur before didSelectRowAtIndexPath
Do you have your detail segue attached to the table view cell? Instead, try dragging it between the two view controllers (the one containing the table and the one where you want it to go).
Then perform it manually ([self performSegueWithIdentifier:@"MySegue"];
) when tableView:accessoryButtonTappedForRowWithIndexPath:
.
How to access segue in 'didSelectRowAtIndexPath'?
You should be using the didSelectRowAtIndexPath
method to determine whether or not a cell was selected, and send the indexPath
as the sender of the segue:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showQuestionnaire", sender: indexPath);
}
Then in your prepareForSegue
method, get the indexPath
from the sender
parameter and use that to pass the correct row/data:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "showQuestionnaire") {
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! QuestionnaireController
let row = (sender as! NSIndexPath).row; //we know that sender is an NSIndexPath here.
let patientQuestionnaire = patientQuestionnaires[row] as! PatientQuestionnaire
controller.selectedQuestionnaire = patientQuestionnaire
}
}
To explain...
- I used the index path as the sender so I can easily pass the index path. You could also check for the currently selected cell using other UITableView methods, but I've always done it this way with success
- You can't put
performSegueWithIdentifier
within the prepare for segue method, becauseperformSegueWithIdentifier
leads toprepareForSegue
; You are just looping around and around with no aim. (When you want to perform a segue, prepareForSegue is always executed) prepareForSegue
doesn't run by itself when a row is selected. This is where you needdidSelectRowAtIndexPath
. You need aperformSegueWithIdentifier
outside of the method as described previously, which should be indidSelectRowAtIndexPath
Sending indexPath.row from didselectRowAtIndexPath to prepareForSegue via sender
You should pass like this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("notificationsToAnswers", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "notificationsToAnswers" {
//the below line is incorrect and should be something else
let selectedIndexPath = sender as! NSIndexPath
let index = selectedIndexPath.row
//pass data on using the index
}
}
Related Topics
Uitableview Inside Uiscrollview Not Receiving First Tap After Scrollling
Removing Duplicates from Array of Custom Objects Swift
iOS 5 JSON Parsing Results in Cocoa Error 3840
App Installation Failed Due to Application-Identifier Entitlement
How to Create a Simple Checkbox in iOS
How Does Cellforrowatindexpath Work
Missing Cfbundleiconname in Xcode9 iOS11 App Release
How to Set Device (Ui) Orientation Programmatically
How Does Xcode Find Implicit Target Dependencies
iOS 7 Uitextview Vertical Alignment
Restricting App Installations from Appstore Only to Users with iPhone 5/5S/5C
Reasons for Rejecting iPhone Application by Apple Store
iOS Autolayout with Uiscrollview: Why Does Content View of Scroll View Not Fill the Scroll View
First App Update, User Data Lost (Was Stored in Documents Directory)
Swift - Uibutton with Two Lines of Text
How to Prevent Keyboard Push Up Webview at iOS App Using Phonegap