I'm encountering problems with my UITableViewCells. I connected my UITableView to a API to populate my cells.
Then I've created a function which grabs the indexPath.row to identify which JSON-object inside the array that should be sent to the RestaurantViewController.
Link to my Xcode Project for easier debugging and problem-solving
Here's how my small snippet looks for setting the "row-clicks" to a global variable.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
i = indexPath.row
}
And here's my prepareForSegue() function that should hook up my push-segue to the RestaurantViewController.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let navigationController = segue.destinationViewController as UINavigationController
let vc = navigationController.topViewController as RestaurantViewController
vc.data = currentResponse[i] as NSArray
}
}
And here's how I've set up my segue from the UITableViewCell
Here's my result, I've tried to click every single one of these cells but I won't be pushed to another viewController...I also don't get an error. What is wrong here?
Tried solutions that won't work
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let vc = segue.destinationViewController as RestaurantViewController
//let vc = navigationController.topViewController as RestaurantViewController
vc.data = currentResponse[i] as NSArray
}
}
The problem is that you're not handling your data correctly.
If you look into your currentResponse Array, you'll see that it holds NSDictionaries but in your prepareForSegue you try to cast a NSDictionary to a NSArray, which will make the app crash.
Change the data variable in RestaurantViewController to a NSDictionary and change your prepareForSegue to pass a a NSDictionary
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = redditListTableView.indexPathForCell(cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destinationViewController as RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
For Swift 5
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = self.tableView.indexPath(for: cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destination as! RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
The following steps should fix your problem. If not, please let me know.
Remove your tableView(tableView, didSelectRowAtIndexPath:) implementation.
Make data on RestaurantViewController have type NSDictionary!
Determine the selected row in prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = tableView.indexPathForCell(cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destinationViewController as RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
Dropbox link to stack3 directory
I am having difficulty understanding why your software is much different than a standard 2 level tableview structure. So I coded a short example which you can access from this link. I have also included the sources code below.
The program mimics what you have (as best as I understood it). Table Controller 1 segues to Table Controller 2 from the tableview cell. I had no issues with segue-ing. Notice that I do not have nor need to augment the Storybook to initiate the segue.
I have embedded both the controllers in Navigation Controllers. My experience is that it saves a lot of effort to set up the navigation.
Alternately, I could have control-dragged from the first TableViewController symbol on top of the screen to the second controller and set up the segue.
I used a global variable (selectedRow) although it is not a recommend practice. But you just as easily use the prepareForSegue to set a variable in the RestaurantTableViewController (I show an example)
Finally, I recommend checking the Connections Inspector (for the table view cell in the first controller) to confirm that there is a segue to the second controller. If you control-dragged properly there should be confirmation prompt as well as an entry in the Connections Inspector.
Unfortunately I just cant get the code properly formatter
import UIKit
var selectedRow = -1
class TableViewController: UITableViewController {
var firstArray = ["Item1","Item2","Item3","Item4"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return firstArray.count
}
let nameOfCell = "RestaurantCell"
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = firstArray[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let vc = segue.destinationViewController as RestaurantTableViewController
// can write to variables in RestaurantTableViewController if required
vc.someVariable = selectedRow
}
}
import UIKit
class RestaurantTableViewController: UITableViewController {
var secondArray = ["Item 2.1", "Item 2.2", "Item 2.3", "Item 2.4"]
var someVariable = -1
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return secondArray.count
}
let nameOfCell = "RestaurantCell"
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = secondArray[indexPath.row]
if indexPath.row == selectedRow {
cell.textLabel!.text = cell.textLabel!.text! + " SELECTED"
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
}
I noticed that in your screenshot of your storyboard, the segue is connecting the first prototype cell to the RestaurantViewController. This prototype cell looks like it's the "Basic" style of cell with a disclosure indicator accessory on the right. But look at the screenshot of your app running. The table is being populated with cells that appear to be the "Subtitle" style of cell without a disclosure indicator accessory on the right.
The reason that your segue is never firing no matter what you do is that the segue is only configured to work for a specific prototype cell, but that prototype cell is never being used when you populate the table. Whatever you're doing in tableView:cellForRowAtIndexPath:, you're not using the prototype cell that you want.
#Starscream has the right idea dequeueing the right cell with the right identifier and matching it with the identifier of the prototype cell in Interface Builder. The crash that you're getting even after doing that might be because of the previous problem mentioned in the comments above. Your segue in the storyboard is clearly pointing to a UITableViewController. Your code in prepareForSegue:sender: should be let vc = segue.destinationViewController as RestaurantViewController, as long as RestaurantViewController is a subclass of UITableViewController. You'll crash if you try to cast it as a UINavigationController. Also make sure that the class for the destination UITableViewController in the storyboard is listed as RestaurantController in the Identity Inspector pane. You'll crash if your program compiles thinking that the storyboard just contains a generic UITableViewController there.
Getting back to the original problem more, I don't know how you've implemented tableView:cellForRowAtIndexPath:, which might be crucial. Maybe it's not so simple. Maybe you plan on handling many prototype cells or generate custom cells at runtime. In this case, one way to make this simple for you is to programmatically perform the segue when the user taps on a cell. Instead of using a specific prototype cell, make the segue a connection originating from the "Restauranger nära mig" UITableViewController going to the RestaurantViewController. (Connect in Interface Builder by control-click dragging from the Table View Controller icon at the top of the first one over to the body of the second). You must give this segue an identifier in the Attributes Inspector pane to make this useful. Let's say it's "toRestaurant". Then at the end of your tableView:didSelectRowAtIndexPath: method, put this line of code: self.performSegueWithIdentifier("toRestaurant", sender: self). Now no matter what cell is selected in the table, this segue will always fire for you.
Try creating cells like this in your cellForRow method:
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MyTestCell", forIndexPath: indexPath)
Im going out on a whim here since I am just getting into swift right now but the way I do it in my prepareForSegue() is something like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let navigationController = segue.destinationViewController as UINavigationController
let vc = navigationController.topViewController as RestaurantViewController
//notice I changed [i] to [index!.row]
vc.data = currentResponse[index!.row] as NSArray
}
}
What it looks like to me is that you are calling the i variable which is kind of like a private variable inside a method of your class. You can do something like #Syed Tariq did with the selectRow variable and set it above your class SomeController: UIViewController /*, maybe some more here? */ { and then sign the variable inside your
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
method like above but both ways should work rather well.
I had the same problem and I found the solution to be:
performSegueWithIdentifier("toViewDetails", sender: self)
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var cellnumber = procMgr.processos[indexPath.row].numero
println("You selected cell #\(indexPath.row)")
println(cellnumber)
performSegueWithIdentifier("toViewDetails", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toViewDetails" {
let DestViewController : ViewDetails = segue.destinationViewController as! ViewDetails
}
}
You may need to get the selected cell index of the UItableview. Below code used the selected cell index (UItableview.indexPathForSelectedRow) to get a correct element of the array.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "seguaVisitCardDetial" {
let viewController = segue.destinationViewController as! VCVisitCardDetial
viewController.dataThisCard = self.listOfVisitCards[(tblCardList.indexPathForSelectedRow?.row)!]
}
}
I had this problem, too; the segue from UITableViewCell did not call.
After some searching, I found it is because I had chosen "No Selection" for "Selection" field.
Related
I have seen two similar questions here but none of their answers really helped me.
I have a tableView of comments and I want to perform a segue to a detail of the comment (kind of like twitter does, if you click on a tweet you have a detail view of it). However the information given to the detail view is the penultimate row selected and not the last selected. And if you only select one, the segue wont be even performed.
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("detail_segue", sender: indexPath)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "detail_segue"){
let row = (sender as! NSIndexPath).row;
let commentForSegue = self.AOS[row]
let destinationVC = segue.destinationViewController as! CommentDetailVC
destinationVC.detail_title = commentForSegue.titulo_comment
destinationVC.detail_body = commentForSegue.cuerpo_comment
destinationVC.detail_date = commentForSegue.fecha_comment
destinationVC.detail_num_agree = String(commentForSegue.num_agrees)
destinationVC.detail_num_disagree = String(commentForSegue.num_disagrees)
destinationVC.detail_agreed = commentForSegue.agreed
}
}
I've tried with and without the dispatch_async both on the prepareForSegue and didSelectRowAtIndexPath but it doesnt work. I've also tried doing all the work from the didSelectRowAtIndexPath but no success either.
Thanks!!
First of all, you need to call the segue in the method didSelectRowAtIndexPath and you're calling it from the method didDeselectRowAtIndexPath exist a little difference between both, but are some tips to get the last cell tapped too, see the following code:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// the identifier of the segue is the same you set in the Attributes Inspector
self.performSegueWithIdentifier("detail_segue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "detail_segue"){
// this is the way of get the indexPath for the selected cell
let indexPath = self.tableView.indexPathForSelectedRow()
let row = indexPath.row
let commentForSegue = self.AOS[row]
let destinationVC = segue.destinationViewController as! CommentDetailVC
destinationVC.detail_title = commentForSegue.titulo_comment
destinationVC.detail_body = commentForSegue.cuerpo_comment
destinationVC.detail_date = commentForSegue.fecha_comment
destinationVC.detail_num_agree = String(commentForSegue.num_agrees)
destinationVC.detail_num_disagree = String(commentForSegue.num_disagrees)
destinationVC.detail_agreed = commentForSegue.agreed
}
}
I hope this help you.
I know, I know this has been asked a lot of times. I also found this question but the solution it suggested did not work for me.
I am just trying to build an app to demonstrate how to use those things in UIKit (in case I want to use them later on. I can just copy the code).
I have created a View Controller with a table view in it. I wrote a class called PrototypeTableController to act as the view controller class for the view controller I created in the storyboard.
When the user taps on one of the cells, I want another view controller to show, called Prototype Table Content. And different text will be shown if you tap on different cells.
In the storyboard, it's like this:
The text of the label in Prototype Table Content will be different when the user taps on a different cell. This means I need to send data from one view controller to another.
The post mentioned above suggested that I should give the segue an identifier, so I did:
Here is my code:
View controller class for the table view:
class PrototypeTableController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let data = ["Cell1", "Cell2", "Cell3", "Cell4", "Cell5"]
let contents = ["Hello", "Nice", "OMG", "Jesus", "Peace"]
var content: String?
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = data[indexPath.row]
return cell
}
func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return "This is a prototype table view created by Sweeper"
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "my table"
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
content = contents[indexPath.row]
tableView.deselectRowAtIndexPath(indexPath, animated: true)
performSegueWithIdentifier("showContent", sender: tableView)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showContent" {
let destination = segue.destinationViewController as! PrototypeTableContentViewController
destination.contentString = content
}
}
}
View controller class for Prototype Table Content view:
class PrototypeTableContentViewController: UIViewController {
#IBOutlet var tableContent: UILabel!
var contentString: String?
override func viewDidLoad() {
super.viewDidLoad()
tableContent.text = contentString
}
}
I think I did all the things suggested in the post mentioned above. I added an identifier, I called performSegueWithIdentifier
, I also deselected the cell after the tapping.
However, it just doesn't go to the other view controller! It stays on the same controller! Like this:
When the user taps on one of the cells, I want another view controller to show, called Prototype Table Content. And different text will be shown if you tap on different cells.
While you can programmatically call performSegueWithIdentifier, it's a lot of effort that the storyboard can automatically handle for you. Just use a show storyboard segue from your prototype cell to PrototypeTableContentViewController.
prepareForSegue knows which cell you selected because the cell is the sender. All you have to do is set the destination view controller's contentString.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard let controller = (segue.destinationViewController as? PrototypeTableContentViewController where segue.identifier == "showContent", let cell = sender as? UITableViewCell, textLabel = cell.textLabel else {
return
}
controller.contentString = textLabel.text
}
This is very similar to how a template like Master-Detail segues from a cell to show details about a cell (although Apple uses indexPathForSelectedRow to pass the cell's details):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let object = objects[indexPath.row] as! NSDate
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
In either case, the SDK performs the storyboard segue for you; a segue didn't need to be programmatically added or performed.
Make sure your tableview delegate is set. If you are using storyboard, make sure delegate outlet in your storyboard is connected properly. If you are creating tableview by code, then you should do tableView.delegate=self; to set the delegate.
Your code is fine.
And one more thing:
You might need to change this line:
performSegueWithIdentifier("showContent", sender: tableView)
you need to make the sender as the row but not the tableview,so that the prepare for segue will get the sender as row instead of whole tableview.
As you are calling the prepareForSegue overtime you select a row, it makes sense to make the row as sender in performSegueWithIdentifier.
So it would be:
let row=indexPAth.row
performSegueWithIdentifier("showContent", sender: row)
I am am googling around the whole day for a probably simple question but I do not get it right. Hopefully someone can help me.
I have a tableview controller with one prototype cell containing three custom labels.
When I run the app the table view controller will generate about 150 tableview cells with content parsed form a csv-file.
When I click on one of these cells the user will be forwarded two a second view controller showing some additional infotext for his cell selection.
During the same time the user is clicking the tabelview cell a variable will be updated to the corresponding tableview-row-number (e.g. 150 for the last tableview cell.
Now I want to use this variable as reference text within the text shown in the second view controller.
The variable in the tableview controller is "rowSelectedFromList" and will be set by the following code:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var rowSelectedFromList: String
rowSelectedFromList = rowOfItems[indexPath.row].customlabel3!
println(rowSelectedFromList)
}
The "println" is just for checking if it works correctly and it does.
The question is how can I use the variable "rowSelectedFromList" in the second view controller?
Appreciate your help, thanks!
You can add your custom logic in prepareForSegue like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let controller = segue.destinationViewController as? YourSecondController,
indexPath = tableView.indexPathForSelectedRow() {
controller.someVariable = rowOfItems[indexPath.row].customlabel3!
}
}
Replace YourSecondController with class name for second view controller.
Don't forget to create IBOutlet for your UITableView and name it tableView.
You'll want to put something in prepareForSegue as well as a variable in your second view controller. So in your table view controller:
var variableToPass: String!
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
variableToPass = rowOfItems[indexPath.row].customlabel3!.text
performSegueWithIdentifier("SecondControllerSegue", sender: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SecondControllerSegue" {
let destinationController = segue.destinationViewController as! SecondViewController
destinationController.passedVariable = variableToPass
}
}
And in your second view controller you'll want to add the variable that the value will be passed to:
var passedVariable: String!
You can, of course, choose to replace the variable with whatever type you wish to send :)
Good question if you want sort this problem plz follow below code:
class ViewController {
var cvDataArray = cells = NSMutableArray.new()
func viewDidLoad() {
super.viewDidLoad()
cvDataArray.enumerateObjectsUsingBlock({(obj: AnyObject, idx: Int, stop: Bool) in var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("")
cell.textLabel.text = obj["title"]
cells.addObject(cell)
})
tableView.reloadData()
}
func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cells.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return cells.objectAtIndex(indexPath.row)
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var cell: UITableViewCell = cells.objectAtIndex(indexPath.row)
}
}
The code which is working for me is a mixture Phoen1xUK and glyuck answers.
I put both together and ended up with this working version:
For the FirstViewController:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SecondControllerSegue" {
if let indexPath = self.tableView.indexPathForSelectedRow() {
let rowSelectedFromList = rowOfItems[indexPath.row].customlabel3
(segue.destinationViewController as! SecondViewController).rowTransferedFromList = rowSelectedFromList
}
}
}
In the SecondViewController I set up the variable as follows:
var rowTransferedFromList: String!
I have a table in iOS. How to know what cell the user has clicked and pass information? I have been searching and I could find prepareForSegue. Is this the right method?. All the cases I could find were complicated and with a lot of elements. Can anyone apply to this simplified case and explain in a simple way, please. I am learning and for me is hard to understand this part.
let favoriteThings = [
"First",
"Second",
"Third",
]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.favoriteThings.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// create a new instance of UITableViewCell. I give the name "cell" in Attributes > Identifier:
let cell = tableView.dequeueReusableCellWithIdentifier("FavoriteThingCell") as! UITableViewCell
var favoriteThingForRow = self.favoriteThings[indexPath.row]
cell.textLabel?.text = favoriteThingForRow
return cell
}
// How to know what cell was clicked and pass the right information? Is this the right method?:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// the second screen. I select the icon of View Controller and Attributes Inspector > Class and Storyboard ID is: DetallViewController
var secondScene = segue.destinationViewController as! DetallViewController
if let indexPath = self.tableView.indexPathForSelectedRow() {
let selected = favoriteThings[indexPath.row]
}
}
The usual way is to implement the table view delegate method tableView:didSelectRowAtIndexPath:. It's called by the runtime engine when the user taps a cell. In the method you can call performSegueWithIdentifier:sender: and pass the NSIndexPath instance as parameter sender.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("MyIdentifier", sender: indexPath)
}
The method prepareForSegue:sender: is also called automatically right before the segue is performed to be able to setup things. As you have the selected index path you can retrieve the appropriate datasource item
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// the second screen. I select the icon of View Controller and Attributes Inspector > Class and Storyboard ID is: DetallViewController
var secondScene = segue.destinationViewController as! DetallViewController
let indexPath = sender as! NSIndexPath
let selected = favoriteThings[indexPath.row]
}
I have a UITableView that populates Cells with data based on a JSON call. like so:
var items = ["Loading..."]
var indexValue = 0
// Here is SwiftyJSON code //
for (index, item) in enumerate(json) {
var indvItem = json[index]["Brand"]["Name"].stringValue
self.items.insert(indvItem, atIndex: indexValue)
indexValue++
}
self.tableView.reloadData()
How do I get the label of the cell when it is selected and then also pass that to another ViewController?
I have managed to get:
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
println(currentCell.textLabel.text)
}
I just cant figure out how to pass that as a variable to the next UIViewController.
Thanks
Passing data between two view controllers depends on how view controllers are linked to each other. If they are linked with segue you will need to use performSegueWithIdentifier method and override prepareForSegue method
var valueToPass:String!
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
valueToPass = currentCell.textLabel.text
performSegueWithIdentifier("yourSegueIdentifer", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "yourSegueIdentifer") {
// initialize new view controller and cast it as your view controller
var viewController = segue.destinationViewController as AnotherViewController
// your new view controller should have property that will store passed value
viewController.passedValue = valueToPass
}
}
If your view controller are not linked with segue then you can pass values directly from your tableView function
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
let storyboard = UIStoryboard(name: "YourStoryBoardFileName", bundle: nil)
var viewController = storyboard.instantiateViewControllerWithIdentifier("viewControllerIdentifer") as AnotherViewController
viewController.passedValue = currentCell.textLabel.text
self.presentViewController(viewContoller, animated: true , completion: nil)
}
You asked:
How do I get the label of the cell when it is selected and then also pass that to another ViewController?
I might suggest rephrasing the question as follows: "How do I retrieve the data associated with the selected cell and pass it along to another view controller?"
That might sound like the same thing, but there's an important conceptual distinction here. You really don't want to retrieve the value from the cell label. Our apps employ a MVC paradigm, so when you want to pass data information from one scene to another, you want to go back to the model (the items array), not the view (the text property of the UILabel).
This is a trivial example, so this distinction is a bit academic, but as apps get more complicated, this pattern of going back to the model becomes increasingly important. The string representation from the cell is generally is a poor substitute for the actual model objects. And, as you'll see below, it's just as easy (if not easier) to retrieve the data from the model, so you should just do that.
As an aside, you don't really need a didSelectRowAtIndexPath method at all in this case. All you need is a segue from the table view cell to the destination scene, give that segue a unique identifier (Details in my example), and then implement prepare(for:sender:):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DetailsViewController {
let selectedRow = tableView.indexPathForSelectedRow!.row
destination.selectedValue = items[selectedRow]
}
}
Alternatively, if your segue is between the cell and destination scene, you can also use the sender of the prepare(for:sender:):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DetailsViewController {
let cell = sender as! UITableViewCell
let selectedRow = tableView.indexPath(for: cell)!.row
destination.selectedValue = items[selectedRow]
}
}
But the idea is the same. Identify what row was selected, and retrieve the information from the model, the items array.
The above is Swift 3. For Swift 2.3, please see the previous version of this answer.
Okay..Its been 2 days I was searching for the answer that how could I be able to save the selected UITableViewCell label text data and display that data to an another label on an another View Controller which will come out after tapping on a cell. At last I have completed with the task and its successful. Here is the complete code with steps using Swift.I am using Xcode 6.4.
Step 1.
I have Two class assigned to the storyboard view controllers named "iOSTableViewControllerClass.swift" which is a Table View Controller and "iOSTutorialsViewControllerClass.swift" which is a normal View Controller.
Step 2.
Now make segue from iOSTableViewControllerClass to iOSTutorialsViewControllerClass by Control-dragging on the storyboard area and choose "show" from drop down menu. Click on this highlighted button according to the below image and perform the segue.
Step 3.
Now select the segue by clicking on the storyboard and give it an identifier on the Attributes Inspector. In this case I named it as "iOSTutorials"
Step 4.
Now on this step put a label on your cell as well as on the other view controller and make outlets of them on their corresponding classes.
In my case those are "#IBOutlet weak var iOSCellLbl: UILabel!" and " #IBOutlet weak var iOSTutsClassLbl: UILabel!".
Step 5.
Make a string type variable on the first Table View Controller Class. I did this as "var sendSelectedData = NSString()" also Make a string type variable on the second class. I did this as "var SecondArray:String!".
Step 6.
Now we are ready to go.
Here is the complete Code for first Class --
// iOSTableViewControllerClass.swift
import UIKit
class iOSTableViewControllerClass: UITableViewController, UITableViewDataSource,UITableViewDelegate {
// Creating A variable to save the text from the selected label and send it to the next view controller
var sendSelectedData = NSString()
//This is the outlet of the label but in my case I am using a fully customized cell so it is actually declared on a different class
#IBOutlet weak var iOSCellLbl: UILabel!
//Array for data to display on the Table View
var iOSTableData = ["Label", "Button", "Text Field", "Slider", "Switch"];
override func viewDidLoad() {
super.viewDidLoad()
//Setting the delegate and datasource of the table view
tableView.delegate = self
tableView.dataSource = self
//Registering the class here
tableView.registerClass(CustomTableViewCellClassiOS.self, forCellReuseIdentifier: "CellIDiOS")
//If your using a custom designed Cell then use this commented line to register the nib.
//tableView.registerNib(UINib(nibName: "CellForiOS", bundle: nil), forCellReuseIdentifier: "CellIDiOS")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return iOSTableData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let CellIDentifier = "CellIDiOS"
//In this case I have custom designed cells so here "CustomTableViewCellClassiOS" is the class name of the cell
var cell:CustomTableViewCellClassiOS! = tableView.dequeueReusableCellWithIdentifier(CellIDentifier, forIndexPath: indexPath) as? CustomTableViewCellClassiOS
if cell == nil{
tableView.registerNib(UINib(nibName: "CellForiOS", bundle: nil), forCellReuseIdentifier: CellIDentifier)
cell = tableView.dequeueReusableCellWithIdentifier(CellIDentifier) as? CustomTableViewCellClassiOS
}
//Here we are displaying the data to the cell label
cell.iOSCellLbl?.text = iOSTableData[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label text here and storing it to the variable
let indexPathVal: NSIndexPath = tableView.indexPathForSelectedRow()!
println("\(indexPathVal)")
let currentCell = tableView.cellForRowAtIndexPath(indexPathVal) as! CustomTableViewCellClassiOS!;
println("\(currentCell)")
println("\(currentCell.iOSCellLbl?.text!)")
//Storing the data to a string from the selected cell
sendSelectedData = currentCell.iOSCellLbl.text!
println(sendSelectedData)
//Now here I am performing the segue action after cell selection to the other view controller by using the segue Identifier Name
self.performSegueWithIdentifier("iOSTutorials", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//Here i am checking the Segue and Saving the data to an array on the next view Controller also sending it to the next view COntroller
if segue.identifier == "iOSTutorials"{
//Creating an object of the second View controller
let controller = segue.destinationViewController as! iOSTutorialsViewControllerClass
//Sending the data here
controller.SecondArray = sendSelectedData as! String
}
Here is the complete code for the second Class..--
// iOSTutorialsViewControllerClass.swift
import UIKit
class iOSTutorialsViewControllerClass: UIViewController {
//Creating the Outlet for the Second Label on the Second View Controller Class
#IBOutlet weak var iOSTutsClassLbl: UILabel!
//Creating an array which will get the value from the first Table View Controller Class
var SecondArray:String!
override func viewDidLoad() {
super.viewDidLoad()
//Simply giving the value of the array to the newly created label's text on the second view controller
iOSTutsClassLbl.text = SecondArray
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I do it like this.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedName = nameArray[indexPath.row]
let newView: nextViewName = self.storyboard?.instantiateViewController(withIdentifier: "nextViewName") as! nextViewName
newView.label.text = selectedValue
self.present(newView, animated: true, completion: nil)
}