How to send didSelectRowAtIndexPath back to view controller in swift - swift

I have 1 viewController and 1 tableViewController in swift. I can send an NSMutableArray from the viewController to populate the tableViewController using segue. I do not know how to send the selected row back to the view controller. The code so far:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("You selected cell #\(indexPath.row)!")
// Missing code for sending back the selected row
self.dismissViewControllerAnimated(true, completion: nil)
}
Any ideas?

You can use the delegation pattern. Create a protocol:
protocol MyDataDelegate {
didSelectRow(row: NSIndexPath, data: MyData)
}
In the table controller, add a property:
var myDataDelegate: MyDataDelegate?
and in the didSelectRowAtIndexPath call the delegate method:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("You selected cell #\(indexPath.row)!")
let data = getDataForRow(indexPath) // <== You need to implement it
self.myDataDelegate?.didSelectRow(indexPath, data: data)
self.dismissViewControllerAnimated(true, completion: nil)
}
Next, in your main view controller:
implement the MyDataDelegate protocol
implement the MyDataDelegate.didSelectRow method
right before presenting the table controller (or after creating it, if you manually do it), set the myDataDelegate property of the table controller to self
This way, when a row is selected in your table controller, the didSelectRow method is called on your main view controller, so you can do whatever you need with the index path and/or the data.
Of course feel free to change the didSelectRow signature (use the indexpath, or a row index, with or without data, etc.)

Related

Swift segue negating other functions connected to segue object

In a table view controller, I'm trying to get the index of the row that is selected before I segue (will pass this info in prepare for segue eventually). I have implemented this function:
var selectedQuestionCell: IndexPath?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedQuestionCell = indexPath
}
This was working great for me initially. I was able to snag the index of the selected row in my table. However, I want to perform a segue when a row is tapped which will transfer to another View. I connected a segue to my cell (dynamic prototypes). After connecting a segue, my override function no longer executes! I'm really new to Table View Controllers, so I'm not sure if there's anyway I can manually execute this.
To summarize: my problem is after connecting a segue to my cells, the override function to get their index is no longer called. How can I fix this?
Try these thing
Create a new segue from your tableview to another view and name it as you like.
Now add this code inside your didSelectRowAt
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let viewController = storyboard?.instantiateViewController(withIdentifier: "your_segue_name_here") as! YourViewControllerName
self.navigationController?.pushViewController(viewController, animated: true)
}
Please make sure that your tableview is connected with navigation controller.
To do that select your tableView then click on Editor -> Embed In -> Navigation Controller from your Xcode.
I hope it works for you.
: D

How to modify a custom cell inside of DidSelectRowAtIndexPath

A custom cell class has the override func layoutSubviews() where the detailTextLabel of each cell is given the title "Jim". Upon clicking on DidSelectRowAtIndexPath, is there a way to change the detail text of the cell permanently(to stop the cell from constantly making the detail Jim), to let's say "Bob"?.
//This function is in the custom cell UserCell
class CustomCell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
detailTextLabel?.text = "Jim"
}
///........
}
//In the viewController with the tableView outlet
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
//.....
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellId, forIndexPath: indexPath) as! CustomCell
//......
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
/* Code I need to convert the detailTextLabel.text to equal "Bob" upon clicking on certain cell */
}
The cell itself shouldn't be used to hold state for any data, but only to display it. Create a mutable array property on the controller to hold the underlaying data (strings). Set the new cells' text properties by reading this array, and in tableView:didSelectRowAtIndexPath: change the value in the array at the index for "Bob" to "Jim". Whenever the tableView reloads it will now read the updated value from the dataSource.
In addition to the UITableViewDelegate protocol also study the UITableViewDataSource protocol. By default the UITableViewController class conforms to both of these protocols and is assigned as each on its .tableView property (if you introspect its self.tableView.delegate and self.tableView.datasource values you will receive back the original UITableViewController). If you manually created your own tableview controller class that inherits from UIViewController, then you will need to assign both of these properties on the tableView in order for it to function properly.
Very simple, do it like this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
detailTextLabel?.text = "Bob"
}

Swift leave a row selected after changing viewcontroller

i have a two view application. If i select a row a segue load the second view Controller. I want that when i return back to my first controller the row is is still selected. I have tried with this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.cellForRowAtIndexPath(indexPath)!
self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: UITableViewScrollPosition.None)
}
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
but when returning back the row not remain selected. What's is the problem??
P.S.: I want no multiple selection, only one row at time.
If you are using a UITableViewController subclass as your source view controller, what I presume because you are overriding the table view delegate methods, you can use the flag clearsSelectionOnViewWillAppear on your view controller to get this behavior.
override func viewDidLoad() {
self.clearsSelectionOnViewWillAppear = false
}
Or you can set this in your Storyboard as well, when selecting the attributes selector of your source table view controller, you have to untick the Clear on Appearance checkbox.

Storyboard TableView with Segues to Multiple Views

I am having an issue with designing a storyboard. I currently have an app in the app store that was designed with XIB files. I have a tableView placed on a UIViewController - not a tableViewController - that loads a unique viewController for each row that is selected.
I am trying to convert this concept to a storyboard. I've done the following
Place a UIViewController in the Storyboard.
Place a UITableView on the UIViewController so I can customize the table view.
I tried making connections to multiple ViewControllers from the UITableViewCell and I am not allowed.
I tried creating multiple segues from the UIViewController - which I can - but when I click on the cells the segues are not fired. I tried using didSelectRowAtIndexPath: and prepareForSegue:
Since this did not work I tried creating a project with a UITableViewController and then created multiple segues from the UITableViewController. I then named each segue and used the didSelectRowAtIndexPath: method to test the selected cell and called performSegueWithIdentifier: and this did not work. As I clicked on cells I would get random loading of the incorrect viewController. I've copied a bit of my code and few screen shots below.
I am wondering if I am blatantly missing something obvious or do I have to revert to a xib format for this type of project?
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)
{
if indexPath.row == 0
{
println("Segue1")
self.performSegueWithIdentifier("Segue1", sender: self)
}
else if indexPath.row == 1
{
println("Segue2")
self.performSegueWithIdentifier("Segue2", sender: self)
}
else if indexPath.row == 2
{
println("Segue3")
self.performSegueWithIdentifier("Segue3", sender: self)
}
}
Take care,
Jon
The method
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) is called when an item is deselected.
To call a method when an item is selected, change the method name to override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
I used a combination of the comment by Allen. Initially I wasn't able to create the segues I needed. I created a navigation controller that uses my own view controller that holds a tableview. Then I created the associated cells for the prototype cells and switched them to a static cell. I only have a limited amount, 3 at the time. This allowed me to created the segues to the appropriate views in the storyboard. Then I changed the cells back to prototype cells and it maintained the connection to the segues. All that is left was creating the associated switch statement in the table view to go to the correct segue. Just make sure you name your segues with the identifiers listed in your code.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath:NSIndexPath) {
//Add cases here to move to different segues
switch indexPath.row{
case 0: self.performSegueWithIdentifier("courses", sender: self);
break;
case 1: self.performSegueWithIdentifier("finals", sender: self);
break;
case 2: self.performSegueWithIdentifier("academic", sender: self);
break;
default:
break
}
}
Swift 3 Code
Well, look at my piece of code I use to perform dynamic segue based on the type of the device type in the cell. :) Hope it helps.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let device = Cache.DEVICELIST[indexPath.row]
let deviceType = device.type
switch deviceType {
case "camera":
self.performSegue(withIdentifier: "DashCellToCamera", sender: self)
case "gateway" :
self.performSegue(withIdentifier: "DashCellToGateway", sender: self)
case "tracker" :
self.performSegue(withIdentifier: "DashCellToTracker", sender: self)
case "panicbutton" :
self.performSegue(withIdentifier: "DashCellToPanicButton", sender: self)
default:
break
//do nothing just ignore this
}
}

Push view controller when cell is tapped

I have tableViewController which pulls data from Parse. This calls inherits from UINavigationControllerDelegate.
I want to push a new view controller when the user taps on a cell. It seems like a simple task but I can't get it to work. I have first tried just simply making a push segue in my storyboard but nothing happens when I tap on the cell. I have tried to do it programmatically but the app crashes when I tap on the cell. I get a breakpoint error on the instantiation line:
import UIKit
import Foundation
import Parse
class PFViewController: PFQueryTableViewController, UITableViewDataSource, UINavigationControllerDelegate {
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let vc: Podcast = self.storyboard?.instantiateViewControllerWithIdentifier("Podcast") as Podcast
self.navigationController?.pushViewController(vc, animated: true)
}
}
Any ideas please?
To create the segue, ctrl-drag from the TableViewController to the destination viewController:
Then select the segue and give it an identifier in the property inspector:
Now you are able to perform this segue in code:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
performSegueWithIdentifier("mySegue", sender: cell)
}