ios Swift: Passing data from tableView to view controller - ios

enter image description herewell this is my first time posting a question so not to sure how it works. I am doing an assignment on swift. I am stuck at a point where I need to pass the data from tableview to viewcontroller. On my first ViewController, I have a list of data (Categories) coming from the database table and when the user clicks on any of the cell, it should go to the next viewcontroller the label becomes the heading. Please find my screen shot attached.
Thanks
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CategoryList_TableViewCell
let maindata = values[indexPath.row]
cell.categoryLabel.text = maindata["NAME"] as? String
return cell;
}
I tried using didSelectRowAtIndexpath and perparesegue functions but not getting my head around.
can anyone can guide me.
Thanks a million in advance :)

You don't need to implement didSelectRow just to pass data through a segue. Assuming you're using Storyboards.
CTRL drag from the prototype TableViewCell in your storyboard to the ViewController you want to pass data to.
Choose Show for the segue type and give it an identifier
Do this in prepareForSegue:
if segue.identifier == "catView" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let controller = segue.destinationViewController as! YourViewController
let value = values[indexPath.row]
controller.catTitleRec = value["NAME"] as! String
}

Do this in your didSelectRowAtIndexPath:
let maindata = values[indexPath.row]
self.performSegueWithIdentifier("yourIdentifier", sender: mainData)
Then, in your prepareForSegue function do this:
let destinationVC = segue.destinationViewcontroller as! YourCustomViewController
destinationVC.yourObject = sender as! YourObject

Related

Send information to another View controller

I am having trouble getting the Indexpath of table view cell and sending it to a next page.
var bookName: String?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cells", for: indexPath) as! ProfileTableViewCell
print(posts[indexPath.row])
let post = self.posts[indexPath.row] as! [String: AnyObject]
self.bookName = post["title"] as? String
}
override public func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "sendMessageToUser", let chatVc = segue.destination as? SendMessageViewController else {
return
}
chatVc.bookName = self.bookName
}
So I am trying to capture the title of whatever cell I clicked and send it to SendMessageViewController. The issue is that it captures some titles accurately and sometimes it does not capture the titles accurately, and I am not sure why.
You need to implement the table view delegate method tableView(_:didSelectRowAt:). In that method, save the selected indexPath to an instance variable and invoke your segue.
Then in prepareForSegue, use the saved indexPath to index into your data model and fetch the data for the selected cell. (The title string, in your case.) Don't fetch the data from the cell's views. Views are not for storing data.
cellForRowAt method serves to create view, in this case a table view cell, and then provide that to table view to display. When table view loads data, you will see, say 10 cells. So this function is called 10 times to prepare the 10 cells. So in the last time, the index row will be 9 and your bookName property will be the 10th of your post array.
Now say you scroll down a bit and then scroll all the way up, the last cell getting prepared is the first cell. So now your bookName will be the first of your post array. That's why you are getting incorrect book name.
To fix your problem, you need to get the specific book name only after user clicked on a cell. So remove the code that assign values to bookName in your cellForRow method, and then add another delegate function like this
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let post = self.posts[indexPath.row] as! [String: AnyObject]
self.bookName = post["title"] as? String
}

Swift Button inside CustomCell (TableView) passing arguments to targetMethod

My TableView features custom Cells which have a button to display corresponding detailed info in another view.
This thread here got me started and I tried to implement the approach with the delegate inside the customCell:
How to access the content of a custom cell in swift using button tag?
What I want to achieve is that when I click on the button it reads the name of the cell and passes it on to the next controller. However it seems that I cannot pass the name with the delegate method and its field is nil.
How can I get the specific content of a cell when clicking on its button?
This is what I did so far:
In the class creating my own cell I set delegate:
protocol CustomCellDelegate {
func cellButtonTapped(cell: DemoCell)
}
(........)
var delegate: CustomCellDelegate?
#IBAction func buttonTapped(sender: AnyObject) {
delegate?.cellButtonTapped(self)
}
In the TableViewController I have the following:
override func tableView(tableView: UITableView, cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCellWithIdentifier("FoldingCell",
forIndexPath: indexPath) as! DemoCell
cell.delegate = self
//TODO: set all custom cell properties here (retrieve JSON and set in cell), use indexPath.row as arraypointer
let resultList = self.items["result"] as! [[String: AnyObject]]
let itemForThisRow = resultList[indexPath.row]
cell.schoolNameClosedCell.text = itemForThisRow["name"] as! String
cell.schoolNameOpenedCell.text = itemForThisRow["name"] as! String
self.schoolIdHelperField = itemForThisRow["name"] as! String
cell.schoolIntroText.text = itemForThisRow["name"] as! String
//call method when button inside cell is tapped
cell.innerCellButton.addTarget(self, action: #selector(MainTableViewController.cellButtonTapped(_:)), forControlEvents: .TouchUpInside)
cell.school_id = itemForThisRow["name"] as! String
// cell.schoolIntroText.text = "We from xx University..."
return cell
}
And finally the target method when the button inside the cell is clicked
func cellButtonTapped(cell: DemoCell) {
print("the school id: ")
print(cell.schoolNameOpenedCell) //this line throws an error EXC_BAD_ACCESS 0x0
}
Firstly, the object innerCellButton is not a Cell, it's a button. The simple way to solve your problem is, just refer the index of the button. Please find the below method.
func cellButtonTapped(AnyObject: sender) {
let resultList = self.items["result"] as! [[String: AnyObject]]
//Get the tag value of the selected button.
//Button tag should be matching with the corresponding cell's indexpath.row
let selectedIndex = sender.tag
let itemForThisRow = resultList[selectedIndex]
print("the school id: \(itemForThisRow[\"name\"])")
}
* And set each button's tag as indexPath.row *
E.g.,
override func tableView(tableView: UITableView, cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
// Dequeue your cell and other code goes here.
// set the button's tag like below.
cell.innerCellButton.tag = indexPath.row
return cell
}
Close. I wouldn't use Suresh's method since it does not help find the IndexPath, which includes section and row.
First, I would recommend a model object for your table view data source. Learn more about the MVC pattern as well as parsing a JSON response to an object with mapping. However, this would give you the data you want.
func cellButtonTapped(cell: UITableViewCell) {
let indexPath = tableView.indexPathForCell(cell)
let resultList = self.items["result"] as! [[String: AnyObject]]
let itemForThisRow = resultList[indexPath.row]
let name = itemForThisRow["name"] as! String
}

PrepareForSegue with UITableViewController - Pass data

I am having a huge problem with my code. My question is, how can I get the data from the tableviewcell the user clicks on to a detail viewcontroller.
I am already getting the data out of an array and displaying it in my tableviewcontroller, but how can I pass that data through to a new viewcontroller using prepareForSegue?
This is my code for displaying data in the cells.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "MealTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! MealTableViewCell
// Fetches the appropriate meal for the data source layout.
let meal = meals[indexPath.row]
cell.nameLabel.text = meal.name
cell.photoImageView.image = meal.photo
cell.descriptionLabel.text = meal.description
cell.servedWithLabel.text = meal.servedWith
return cell
}
The problem is, that calling a prepareForSegue outside of that means that I cannot use for instance meal.name to pass the name through to the detail viewcontroller? What to do?
Hope you guys can help me - I have been struggling with this for some time now :-(
As pointed out by Arun, you need to use -prepareForSegue. Here's what I'd do to pass something to your detail view controller (say meal.name)
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Use this to determine the selected index path. You can also store the selected index path in a variable using -didSelectRowAtIndexPath
let cell = sender as! UITableViewCell
let indexPath = self.tableView.indexPathForCell(cell)
// Get the relevant detail
let meal = meals[indexPath.row]
// Create reference and pass it
let detailViewController = segue.destinationViewController as! MyDetailViewController
detailViewController.mealName = meal.name
}
And eventually, just hook up the UITableViewCell with MyDetailViewController using your Storyboard (and select whatever presentation and transition style you prefer)
Edited for Swift 4
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let cell = sender as! UITableViewCell
let indexPath = self.tableView.indexPath(for: cell)
// Get the relevant detail
let meal = meals[indexPath!.row]
// Create reference and pass it
let detailViewController = segue.destination as! MyDetailViewController
detailViewController.mealName = meal.name
}
When you click a cell. It will call didSelectRow. In didSelectRow save the indexPath.row and do performseguewithidentifier
Now in prepareForSegue get the object from the array using meals[selectedIndex] and assign to detailViewController Objects.
Make sure segue is from ViewController to ViewController.

How to pass cell label's value from tableView to other View?

I am a beginner in IOS programming, and in a whole programming.
(I have XCODE 6.4)
I have read so many tutorials, but i haven't found the information I need.
I have a code which assign a value to a label :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let identifier = "formuleTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as! formule
let formuleCommand = formulesList[indexPath.row]
// Configure the cell...
var shortCut = formuleCommand.formuleText
cell.formuleLabel.text = shortCut
return cell
}
And then, I have a code, which have to get the label's name (I think so)
var valueToPass:String!
func tablView(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 identifier = "formuleTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath!) as! formule
valueToPass = cell.formuleLabel.text
performSegueWithIdentifier("detail", sender: self)
}
And finally, code, which passes the data from label to another ViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "detail") {
// initialize new view controller and cast it as your view controller
var viewController = segue.destinationViewController as! specialitiesViewController
// your new view controller should have property that will store passed value
viewController.passedValue = valueToPass
}
}
It have to work so:
Table view gets the data for cells (here is no code for this)
Then, method called TablView have to get cell's label.
And finally, i click on the cell and I move to another ViewController, where my Cell,s Label data prints in another Label.
But it don't work so, when I click on cell, I move to ViewController and the text in Label equals nil (i see no text). Why does it work so? Help me to fix this issue!
Thank you, for all your suggestions!
Your problem is that you're using the functiondequeueReusableCellWithIdentifier for get the cell and and this method only returns a cell if it has been marked as ready for reuse.
You need to use cellForRowAtIndexPath that is different from the delegate method, be carefull to get the cell, change your didSelectRowAtIndexPath like the following:
func tablView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// get cell label
let cell = tableView.cellForRowAtIndexPath(indexPath) as! formule
self.valueToPass = cell.formuleLabel.text
self.performSegueWithIdentifier("detail", sender: self)
}
I hope this help you.

Custom CollectionView Cell PrepareForSegue

I have a custom UICollection View Cell. One of that cell's property's is cellImageView. When the user selects a cell, I want to pass the image from that view (cellImageView.image) to the next one. Here's what I've tried:
if let indexPath = self.collectionView?.indexPathForCell(sender as! UICollectionViewCell)
{
if segue.identifier == "show"
{
var segue = segue.destinationViewController as! ViewPhoto
segue.imageURL = URLToPass
}
}
but quickly realized that's the wrong route to take. What's the best way to go about doing this? Thanks in advance.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
if let cell = self.collectionView.cellForItemAtIndexPath(indexPath) as? GalleryClass
{
let imageToPass = cell.cellImageView.image
self.performSegueWithIdentifier(mySegue, sender: imageToPass)
}
}
And in your prepareForSegue function:
if segue.identifier == "show"
{
var segue = segue.destinationViewController as! ViewPhoto
// segue.imageURL = URLToPass
segue.image = sender as! UIImage
}
This way you're keeping code which contains CollectionView stuff in the own delegate method, which is easier to maintain if you have to change it in the future. And you only pass data in your prepareForSegue function which you actually need in there.

Resources