How to send UITableViewCell data to another ViewController in swift? - swift

I am trying to send a single message from the messageArray to another UIViewController so that I can load up the message's comments. How can I send the message data structure over when the cell is clicked on?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell") as? feedMessagesCell else {return UITableViewCell()}
let message = messageArray[indexPath.row]
cell.configureCell(content: message.content, userName: message.userName)
return cell
}

First of all don't guard reusing cells. The code must not crash. If it does it reveals a design mistake. And use the API which returns a non-optional cell.
let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell", for: indexPath) as! feedMessagesCell
To send data to another view controller create a segue in Interface Builder by connecting the table view cell to the destination controller.
In prepare(for segue the sender is the cell. Change PushFeedDetail to the real identifier and MyDestinationController to the real class. Create a message property in the destination controller. Get the index path from the cell and pass the item in the data source array.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "PushFeedDetail" {
let selectedIndexPath = tableView.indexPath(for: sender as! feedMessagesCell)!
let destinationController = segue.destination as! MyDestinationController
let message = messageArray[selectedIndexPath.row]
destinationController.message = message
}
}

Related

How to Send a segue in didSelectItemAt

I am trying to make a segue that sends a string to a variable in the next view controller. This string is the text inside a label that is inside a collection view cell, the text inside the label is from CoreData. When the user presses the cell, it is meant to segue to the next view controller and have the text of the cell previously selected in a variable. I am not sure how to do this, this is my didSelect function which is able to get the text of the selected cell:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellP", for: indexPath) as! CCCollectionViewCell
let project = projectList[indexPath.row]
if project.name! == "Hi " {
print("Yes")
}
else {
print("no")
}
print(project.name!)
}
The problem is I am not sure how to send this value (project.name!) of the selected cell in a segue to the next view controller variable.
Try like this way.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! NextViewController //Your ViewController class
if let cell = sender as? UICollectionViewCell,
let indexPath = self.collectionView.indexPath(for: cell){
let project = projectList[indexPath.row]
print(project.name)
vc.name = project.name
}
}
Now simply in your NextViewController create one property of type String.
var name = String()

pass data from tableview to view controller

I am writing a Xcode program in Swift. I have a tableview controller with some labels and an image per cell. They have their data from a first view controller. So far so good. Now i would like the user to tap a cell which opens a new controller which contains the same label and image data as the cell. With the following code the new controller opens, nonetheless I don't no how to transfer the data. If someone could help me I would be so so grateful.
Here are the codes that i tend to use:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "TableView"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! TableView
let picture = pic[indexPath.row]
cell.label1.text = picture.name1
cell.photoImage.image = picture.photo
cell.label2.text = picture.name2
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let cell = indexPath.row
self.performSegueWithIdentifier("segue", sender: cell)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segue"{
var row = tableView.indexPathForSelectedRow
let viewController = segue.destinationViewController as! vc2
}
}
PS:I have a segue from the image to the new controller with the identifier "segue".
PPS: Of course i have tried the following method: Send data from TableView to DetailView Swift but when i run my program I get an error with the information that my labels were unexpectedly found nil
You should not need to override didSelectRowAtIndexPath or call performSegueWithIdentifier to do this. Connect your segue in the IB file dragging from a table view controller's cell to the second controller. You should then pass the data to the controller in prepareForSegue, in the segue.destinationViewController. You set the public properties on that destination controller.
Also make sure your labels in your prototype cell have been connected in IB. If they are they, should not be nil. Set a breakpoint on the cellForRowAtIndexPath to verify this.
Unless you are talking about the labels in your destination controller. These also need to be hooked up in IB. You would then set them in prepareForSegue. You would get the appropriate data from the
let viewController = segue.destinationViewController as! vc2
var path = tableView.indexPathForSelectedRow
viewController.destLabel.text = arrayData[path.row].myData // or whatever data you have from your model.

Linking tableview cell information to a view controller

I'm pretty new to Swift. I wish to reflect tableview cell data (title and description of a post) in a new view controller. Here's the code I put in the first view controller (which contains the tableview cell).
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
let indexPath = tableView.indexPathForSelectedRow()!
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as! PostCell!
let post = posts[indexPath.row]
valuetoPass = post.title
valuetoPass_desc = post.postDescription
performSegueWithIdentifier("seguetoVC", sender: self)
}
And this one...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "seguetoVC" {
let viewController = segue.destinationViewController as! UpdateVC
viewController.toPassTitle = valuetoPass
viewController.toPassDesc = valuetoPass_desc
}
}
Here's a part of UpdateVC..Added the variables, toPassTitle and toPassDesc...And these are the lines I added to viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
self.postTxt.delegate = self
self.descTxt.delegate = self
descTxt.text = toPassTitle
postTxt.text = toPassDesc
}
Just wondering what I'm doing wrong-- viewController.toPassTitle and viewController.toPassDesc keep on returning a null value. Thanks in advance.
You can set the sender parameter to be whatever type you want, there's no reason for it to be self, i.e. the originating view controller if that's not what you need. In fact, there should never be a need to pass the originating view controller as the sender, because you can get it from segue.sourceViewController in prepareForSegue.
In the documentation for prepareForSegue, Apple suggests:
Because segues can be triggered from multiple sources, you can use the information in the segue and sender parameters to disambiguate between different logical paths in your app. For example, if the segue originated from a table view, the sender parameter would identify the table view cell that the user tapped. You could then use that information to set the data on the destination view controller.
Which sounds like exactly the situation you're in. Since you've already figured out the model object for your cell, we can pass that rather than the cell. So, you could call performSegueWithIdentifier("seguetoVC", sender: post), and then change up your prepareForSegue implementation to use the details from the post directly, e.g.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "seguetoVC" {
let viewController = segue.destinationViewController as! UpdateVC
if let post = sender as ? Post {
viewController.toPassTitle = post.title
viewController.toPassDesc = post.postDescription
}
}
}
You don't need to call tableView.cellForRowAtIndexPath(indexPath) as! PostCell! anywhere, and it could be fairly expensive, so don't do it if you don't use it. Your didSelectRowAtIndexPath method might look more like this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let post = posts[indexPath.row]
performSegueWithIdentifier("seguetoVC", sender: post)
}
There's also a bunch more you could do to make it safer, so have a look at unwrapping optionals using constructs such as if let and guard let, which can also help you avoid force casting (!), and potentially crashing your app. I've done that in unwrapping sender to post, so you can see an example there.
You do not need to declare indexPath again. didSelectRowAtIndexPath already has indexPath. Update your codes in didSelectRowAtIndexPath method.
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
let post = posts[indexPath.row]
valuetoPass = post.title
valuetoPass_desc = post.postDescription
performSegueWithIdentifier("seguetoVC", sender: self)
}
On top of that, ensure that in your storyboard, you need to name your segue identifier with seguetoVC also.

Get data from a cell with "willSelectRowAtIndexPath" in Swift2

I'm trying since two weeks with the help of many Tutorials to get and segue data from a TableView cell. But it seems it is impossible to do that in XCode. It is only possible to get the selectedRow of a cell, but I cannot read out the Text labels of a selected cell.
If a user selects a Cell I want to segue the value of a label in the selected cell to a new View Controller.
I can only submit the selected row to a new View Controller but not the value of a label in this selected cell.
func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
row = indexPath.row // here is the row the user has selcted
labelStringOfselectedCell = "??????" // how to retrieve data from a label in the cell?
return indexPath
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let DestViewController : ViewControllerDetail = segue.destinationViewController as! ViewControllerDetail
DestViewController.seguedData = labelStringOfselectedCell
}
If you really wanted to do something like that, you can do something like:
func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
let cell = tableView.cellForRowAtIndexPath(indexPath) // do not confuse this with the similarly named `tableView:cellForRowAtIndexPath:` method that you've implemented
let string = cell?.textLabel?.text
return indexPath
}
Clearly it depends upon whether you're custom cell subclass and what the label was, but that illustrates the basic idea.
Having said that, you should not do this. Your app should be following Model-View-Controller (MVC) programming paradigm. When determining what data to pass to the next scene, you should go back to the original model you used when originally populating the table, not referring to some control in the table.
For example, let's imagine that you populated the original cell by retrieving data from the objects model:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let object = objects[indexPath.row]
cell.textLabel?.text = object.name
return cell
}
Then you would just implement a prepareForSegue that retrieves the data from objects also (and you don't have to implement willSelectRowAtIndexPath at all):
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destination = segue.destinationViewController as? ViewControllerDetail {
let object = objects[tableView.indexPathForSelectedRow!.row]
destination.seguedData = object.name
}
}
Clearly, this will change depending upon what your model was and how you originally populated the cell, but hopefully it illustrates the basic idea.

swift: prepareForSegue indexPathForSelectedRow

I have an UITableView populated by a cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("customTableViewCell") as! UITableViewCell
let task = frc.objectAtIndexPath(indexPath) as! Task
cell.textLabel?.text = task.summary
var detail = task.detail
var context = task.context
var due = task.date
var status = task.status
var responsible = task.responsable
var folder = task.folder
cell.detailTextLabel?.text = "Contexte: \(context), Detail: \(detail), Status: \(status), Ending date: \(due)"
return cell
}
On the storyboard, I have made a segue when clicking one cell of the tableView to open a detailViewController
this is my didSelectRowAtIndexPath:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)
self.name = cell!.textLabel!.text!
println(self.name)
self.performSegueWithIdentifier("Show Detail", sender: indexPath);
}
and the prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let identifier = segue.identifier{
switch identifier {
case "Show Detail":
let indexPath = self.tableView.indexPathForSelectedRow()
let editTaskVC = segue.destinationViewController as! EditTaskViewController
editTaskVC.Name = "cell.textLabel?.text is what I would like to.."
default: break
}
}
}
If I do editTaskVC.Name = indexPath?.description I can see the description of the cell clicked like, <NSIndexPath: 0x78f96ab0>... for example.
Is it possible, instead of printing the description of the indexPath, printing the cell.textLabel?.text of the clicked row?
I have seen many, many tutorials or posts on forum but I haven't succeed to solve my problem...
Thank you for your help.
Regards.
Your intention is to pass along the cell.textLabel?.text to the destination view controller right?
You're taking a needless detour. The sender parameter in performSegueWithIdentifier: can take in an AnyObject, so you can go right ahead and pass it the name.
self.performSegueWithIdentifier("Show Detail", sender: name)
That way, prepareForSegue will have the item you need to pass along to the next view controller. Simply assign editTaskVC = sender as! String and you're good to go.
The piece of knowledge you were missing is that, the sender parameter in performSegueWithIdentifier: sender will automatically pass the sender's contents into prepareForSegue, as the sender parameter.
Since you already have the index path, you can simply invoke the table's cellForRowAtIndexPath to obtain the cell:
if let indexPath = self.tableView.indexPathForSelectedRow() {
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? UITableViewCell {
let editTaskVC = segue.destinationViewController as! EditTaskViewController
editTaskVC.Name = cell.textLabel?.text
}
}
The indexPathForSelectedRow returns nil in 2 cases only:
if the index is out of range
if the cell is not visible