Passing data from tableviewcell to another viewcontroller - ios

I am trying to pass cell's tag data to another viewcontroller's variable
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell!
print(currentCell.tag)
valueToPass = currentCell.tag
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let Dest = segue.destinationViewController as! EventDetail
if (segue.identifier == "eDetay") {
Dest.eventid = String(valueToPass)
}
}
When i try as it is, valueToPass is always passed the previous data.
Is there a way to get selected cell data from prepareForSegue ?
What is the best way to do that?

You are overriding the indexPath parameter that is being passed to you.
Remove the first let statement. Use the indexPath that is being passed to you.

func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!)
{
let cell = tableView.cellForRowAtIndexPath(indexPath) as YourCell
//cell.value, cell.text, cell.randomValue or whatever you need
}

Related

send data from tableviewcontroller to detailviewcontroller

I have a tableviewcontroller named DetailTableViewController and I need to pass data to next tableviewcontroller named DetailTableViewController. But I need to pass the data as the user clicks the cell of DetailTableViewController. Then, I got error as "unexpectedly found nil while unwrapping an Optional value".Please help me sort out in Swift 3.
First of all, never get data from the view (the cell) in such a case, get it always from the model (data source array).
Second of all, the signature of prepare(for segue is wrong for Swift 3.
In didSelectRowAt pass the indexPath rather than self, you can also delete valueToPass.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "Cell", sender: indexPath)
}
In prepareForSegue get the data from the model and pass it to the detail view controller:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Cell" {
let viewController = segue.destination as! GuidesDetailsTableViewController
let indexPath = sender as! IndexPath
viewController.passedValue = guides[indexPath.row]
}
}
First create a variable in your detail view controller to hold the value which you send from first view controller. then assign the value inside the didSelectRowAt method in first view controller and then navigate programatically. in this way, you do not need to implement prepare for segue method to send the data.
you just need to implement the didselectrowat, method.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selected = firstArray[indexPath.row]
let detailvc = self.storyboard?.instantiateViewController(withIdentifier: "DetailTableViewController") as! DetailTableViewController
detailvc.type = selected
self.present(detailvc, animated: true, completion: nil)
}
I created a video tutorial for you from scratch. how to pass data from one table view controller to another. hope this will help to you.
Inside your didSelectRow you're setting a new indexPath. Removing it should do the trick.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Don't reassign indexPath
// let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
valueToPass = currentCell.textLabel?.text
performSegue(withIdentifier: "Cell", sender: self)
}
It seems that the var valueToPass don't have a value when you call the performSegue. Try to assign the value of valueToPass with the following code:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
valueToPass = guides[indexPath.row]
performSegue(withIdentifier: "Cell", sender: self)
}
And create your segue form your viewController, maybe you create the segue from the cell.

didSelectRowAtIndexPath index path with uisearchcontroller

I have an application when the user clicks on a cell it will open another viewController and I just add a uisearchcontroller on my tableview.
When I am searching on the tableview the result is correct ,
but when I click on the cell after filtering , it opens the wrong page.
My problem is I don't now how to identify the indexpath when the uiviewcontroller is active to make the result open correct page
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
IndexPathRow = indexPath.row
performSegueWithIdentifier("toView2", sender: self)
}
Edit
I solved my problem by adding new variable in the struct of type integer and then modify didSelectRowAtIndexPath function to
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if resultSearchController.active && resultSearchController.searchBar.text != ""{
IndexPathRow = filteredData[indexPath.row].i
}
else {
IndexPathRow = indexPath.row
}
performSegueWithIdentifier("toView2", sender: self)
}
A better way to get the selected item, is to call indexPathForSelectedRow() method inside of the segue delegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("toView2", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toView2" {
let indexPath = self.tableView.indexPathForSelectedRow() {
print("IndexPathRow = \(indexPath.row)")
//destination controller code goes here ...
}
}
}
You are getting the data with your main array, try to get the data with the searched array, then only its correct, check for searchController.isActive() on all the method related to the main array, basically check for this in your prepareForSegue

Variable nil when trying to pass variable to view controller with segue

Here is the code I currently have:
var valueToPass:String!
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
valueToPass = currentCell.textLabel.text // valueToPass now equals "test"
performSegueWithIdentifier("yourSegueIdentifer", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var viewController = segue.destinationViewController as AnotherViewController
viewController.passedValue = valueToPass // valueToPass equals nil here? Why?
}
as you can see, i have assigned "test" to valueToPass in didSelectRowAtIndexPath but in prepareForSegue, valueToPass is nil? why?
Try replacing:
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
valueToPass = currentCell.textLabel.text // valueToPass now equals "test"
performSegueWithIdentifier("yourSegueIdentifer", sender: self)
}
With this:
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
let currentCell = tableView.cellForRowAtIndexPath(indexPath.row) as! UITableViewCell;
valueToPass = currentCell.textLabel.text! // valueToPass now equals "test"
performSegueWithIdentifier("yourSegueIdentifer", sender: self)
}
Also, when you made the segue in the storyboard, make sure you DID NOT drag from the tableview to the next viewcontroller. This is because if you do this automatically, then perform segue will be called BEFORE didSelectRow... making it perform the segue before you set the value. Just drag from the viewcontroller that hosts the table view to the new view.

Directing to a different ViewController depending on tableView cell clicked

I am trying to present a viewController depending on which tableView cell is clicked.
Currently if they are all clicked they redirect to the same viewController, how would I alter this?
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewCell
cell.cellLabel.text = self.objects.objectAtIndex(indexPath.row) as! String
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("other", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "other"){
var upcoming: otherViewController = segue.destinationViewController as! otherViewController
let indexPath = self.tableView.indexPathForSelectedRow!
let titleString = self.objects.objectAtIndex(indexPath.row) as! String
upcoming.titleString = titleString
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
Could I do an if else on the cellLabel.text? as in if (cellLabel.text == "option8"){
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("option8", sender: self)
}
}
I am using Swift and xcode7.
Don't and never do comparision with cellLabel.text, consider using indexPath.row for that. Then adding different segues in your storyboard for each view controller you need. Code will be something like that:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 || indexPath.row == 2{
self.performSegueWithIdentifier("other", sender: self)
}
else{
self.performSegueWithIdentifier("other", sender: self)
}
}
Yes, you can.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)
if cell.cellLabel.text == "option8" {
self.performSegueWithIdentifier("other8", sender: self)
}
}
You can check indexpath.row in didSelectrow according to row no you can redirect to perticular controller.

Nil data is passed from tableview detail disclosure with prepareForSegue

I need to pass a string with prepareForSegue from a tableView disclosure link. Here is the prepareForSegue code I use. This is the code I found in several cases when other users needed to do the same thing, but in my case it doesn't work. Problem is with indexPathForSelectedRow() that is nil:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "alertsDetail" {
let detailAlertViewController = segue.destinationViewController as DetailAlertViewController
println(alertTable.indexPathForSelectedRow()) // NIL
if let indexPath = alertTable.indexPathForSelectedRow() {
let entryToPass = unpublishedPhotosObjectId[indexPath.row]
detailAlertViewController.entryId = entryToPass
}
}
}
I named the tableView "alertTable" and not self because the tableview is not a view controller, just a view.
In case needed, here is tableview code:
#IBOutlet weak var alertTable: UITableView!
/////////////TableView - START
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return unpublishedPhotos.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 170
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
tableView.separatorColor = UIColor.clearColor()
let cell = tableView.dequeueReusableCellWithIdentifier("adminAlertsCell") as? adminAlertsCell
var data = unpublishedPhotos[indexPath.row].getData()
let image = UIImage(data: data)
cell!.myImageInCell.image = image
return cell
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
// Add access to cell
let cell = tableView.cellForRowAtIndexPath(indexPath) as? adminAlertsCell
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
println(cell!.banSwitch.on)
}
}
/////////////TableView - END
You should make the segue from the controller instead of directly from the detail disclosure button. Implement the method,
tableView:accessoryButtonTappedForRowWithIndexPath: and call performSegueWithIdentifier:sender: from inside that method. Pass the in-depth as the sender argument so you have access to that in prepareForSegue,
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
let indexPath = sender as NSIndexPath
if segue.identifier == "alertsDetail" {
let detailAlertViewController = segue.destinationViewController as DetailAlertViewController
let entryToPass = unpublishedPhotosObjectId[indexPath.row]
detailAlertViewController.entryId = entryToPass
}
}
Your issue is stated in the comments to your question, and there are several solutions. Perhaps the quickest since you only have one section, is to assign the indexPath.row to the tag of the cell. Then in your prepare for segue, the sender will be your cell. You can get the value out of it. So in your cellForRow method before your return your cell:
cell!.tag = indexPath.row
Then in your prepareForSegue:
let cell = sender as? adminAlertsCell
println(cell!.tag)
Here I am just printing it, but you can use it to pass the row.

Resources