Passing data between table views in swift - ios

Trying to code for about us page using tableviews. I am able to create the first table view for "about us" components
var aboutUs = ["About us", "Contact us", "Privacy policy"]
Have to pass on this items to next table view containing aboutUsDetails
var aboutUsDetails = ["A team of docs and coders ","Contact us at editor#gmail.com","Privacy Policy will be updated soon"]
I have created the segue function like this
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == SegueDetailsTableViewController
{
let detailViewController = segue.destination as! DetailsTableViewController
let myIndexPath = self.tableView.indexPathForSelectedRow!
let row = myIndexPath.row
detailViewController.aboutUsDetails = aboutUs[row]
}
I am a bit confused here because aboutUsDetails is a [String]; and it is not passing on? How do I overcome this?

If you are trying to pass only one string, there is no need to declare aboutUsDetails property as an array of strings, instead let it be just a single string:
In DetailsTableViewController:
Change aboutUsDetails: [String]? to aboutUsDetails: String?
If you are implementing the following code snippets, you should change them as follows:
Change this:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return aboutUsDetails.count
}
to this:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
And change this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// you might want to have a custom cell, you don't have to change it...
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCellId")
cell?.textLabel?.text = aboutUsDetails[indexPath.row]
}
to this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// you might want to have a custom cell, you don't have to change it...
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCellId")
// this is part you should foucing on...
cell?.textLabel?.text = aboutUsDetails
}
Note: you might need to do Optional Binding to display the value of aboutUsDetails as it should (without "Optional("...")").
OR
if you insist to declare aboutUsDetails as an array of strings (which I think that there is no need to do that), you will need to pass your string as an array containing one string, as follows:
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == SegueDetailsTableViewController
{
let detailViewController = segue.destination as! DetailsTableViewController
let myIndexPath = self.tableView.indexPathForSelectedRow!
let row = myIndexPath.row
// here is the change, you are passing your string as the first
// (and the only one) element of 'aboutUsDetails'
detailViewController.aboutUsDetails = [aboutUs[row]]
}
}
Hope this helped.

aboutUs[row] is a single string, aboutUsDetails seems to be an array of strings. You can either change aboutUsDetails to be a String, or pass your data like this:
detailViewController.aboutUsDetails = [aboutUs[row]]

You need to only one changes and very small to below line
detailViewController.aboutUsDetails = [aboutUs[row]]
because aboutUs[row] is string and [aboutUs[row]] is Array of String and you can not assign String to aboutUsDetails which is array of String.

Related

How to uniquely identify each cell in UITableView

I have a UITableView and I am trying to make a segue to another viewcontroller, I need the row number so that I can select a string from an array so that I can display this string in the next view controller, I have this code at the moment.
let tableFrontView = segue.destination as! FCTableFrontViewController
tableFrontView.frontText = path[FlashCardsTableViewCell.init().tag].flashCardFront
the FlashCardsTableViewCell.init().tag is currently returning an int for testing purposes though I am wanting to know what I can replace it with to get me the number of the row which was selected by the user.
Thanks
You can try like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let tableFrontView = segue.destination as! FCTableFrontViewController
let selectedIndexPath = tblView.indexPathForSelectedRow
let selectedRow = (selectedIndexPath?.row)!
print(selectedRow)
}
I assume you are writing the code snippet shown in prepare(for:)?
If that's the case, go to where you perform the segue, which is likely in the didSelectedRowAtIndexPath delegate method. If you don't have such a method, you should implement it.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showTableFrontVC", sender: nil)
}
Replace whatever it is that you are passing as sender now, and replace that with indexPath.row.
performSegue(withIdentifier: "showTableFrontVC", sender: indexPath.row)
Now in prepare(for:), you can unwrap sender as an Int:
let tableFrontView = segue.destination as! FCTableFrontViewController
let rowSelected = sender as! Int
tableFrontView.frontText = path[rowSelected].flashCardFront
Use TableView's delegate method :
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// indetify cell using indexPath.row attribute
}

Master Detail View With Segue

I'm Trying to learn how to do a detail view for my project .
I have a simple tableView with a simple Array data to fill it.
The Table View :
TableView Example
I designed a detail View as well, with static tableViewCells
Detail View example :
Example
I'v Connected both with a segue :
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("Profile", sender: indexPath);
}
I also connected all the labels and images with Outlets i want to change between each cell but i don't how to advance from here.
right now every cell shows the same thing but i want to change the data between rows . So i would like to change the data through the segue and create a master detail application like in my tableview. Can anybody help me ?
Am using Swift 2.3 and Xcode 8.1
If I understand your question correctly, you just want to pass dataSource element to the next viewController. So you can just pick it using indexPath.row and use sender parameter to set it in prepareForSegue method.
The code below assumes your dataSource is self.users array.
Swift 3
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let user = self.users[indexPath.row]
self.performSegueWithIdentifier("Profile", sender: user)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let segueId = segue.identifier? else { return }
if segueId == "Profile" {
guard let profileVC = segue.destination as? ProfileViewController else { return }
profileVC.user = sender as? User
}
}
Swift 2
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let user = self.users[indexPath.row]
self.performSegueWithIdentifier("Profile", sender: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard let segueId = segue.identifier else { return }
if segueId == "Profile" {
guard let profileVC = segue.destinationViewController as? ProfileViewController else { return }
profileVC.user = sender as? User
}
}
Edit
im trying to change data like al the labels you saw between rows like
for example shalvata will have a different data from light house and
so , change the labels and images and so on
It is still unclear for me what data you want to change exactly. Also I don't understand the language on your screenshots, but since you name the relationship as master-detail, I suppose the second screen is meant to show more info about the entity selected on the first screen.
If so, you should start from designing you model so that it contains all those fields you need on the second screen. Judging by the icons it would be something like
struct Person {
var name: String?
var image: UIImage?
var age: Int?
var address: String?
var phone: String?
var schedule: String?
var music: String?
var smoking: Bool?
var car: String?
var info: String?
var hobby: String?
}
Note: Remove ? for those fields which aren't optionals, i.e. always must be set for every entity (perhaps name field)
Usage
I don't known how and when you create your Person array, but basically there are two approaches:
Use a list of entities with all fields filled on MasterVC and just pass the selected person to the DetailVC in didSelectRowAtIndexPath
Use a list of entities with some basic data (name, address, image) required for MasterVC and fill the rest of the fields only when required (didSelectRowAtIndexPath method)
In any case you'll get selected person in DetailVC and now everything you need is to use that data in cellForRow method, just as you did on MasterVC. Perhaps it would be a better option to use static TableViewController for Details screen.
Sounds like what you're trying to do does not involve segues at all. You can change data of cells using the cellForRow method in your tableViewController.
https://developer.apple.com/reference/uikit/uitableview/1614983-cellforrow
For example
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "foo"
return cell
}
If that sounds confusing to you then you should take a step back and do some tutorials then post specific questions on SO.

How do I segue from a tableviewcell and pass different data from each cell to the next tableview?

I'm trying to practice making list apps with models by making a class to represent each list item. I have a Category class which contains three properties - two strings and one array of strings. Here is the class:
class Category {
var name: String
var emoji: String
var topics: [String]
// (the getCategories method listed below goes here) //
init(name: String, emoji: String, topics: [String]) {
self.name = name
self.emoji = emoji
self.topics = topics
}
In my Category class I have a method to assign values to the categories so I can keep them out of the view controller. This method is listed below:
class func getCategories() -> [Category]
{
let categories =
[Category(name:"cat", emoji:"😸", topics:["paws","tails", "fur", "pussyfoot","purr", "kitten", "meow"]),
Category(name: "car", emoji: "🚗", topics: ["motor", "speed", "shift", "wheel", "tire"])
]
return categories
}
I have two UITableViewControllers - CategoryTableViewController and TopicsTableViewController; I want the user to be able to tap a category cell in the CategoryTableViewController and then be taken to the TopicsTableViewController where the topics for the category they selected are displayed in a tableview.
So far I am able to get the cell to segue to the TopicsTableViewController but it displays the same topics no matter which category I select. Here is how I have my didSelectRowAtIndexPath and prepareForSegue set up in the CategoriesTableViewController...
override func tableView(tableView: UITableView,didSelectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "fromCategorySegue") {
let vc = segue.destinationViewController as! TopicsTableViewController
vc.categories = categories
}
}
It displays the first category (cat) topics on the TopicsTableViewController even if I select the second category (car).
In case it is helpful here is a snippet of some of my code in the TopicsTableViewController...
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let topic = categories[indexPath.section].topics[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("topicCell",forIndexPath: indexPath)
cell.textLabel?.text = topic
return cell
}
I also have categories defined at the top of TopicsTableViewController as well so I could get the correct row count based on the topics count...
var categories = Category.getCategories()
I think I'm missing something in my didSelectRowAtIndexPath or in my prepareForSegue. I think the fact that my topics are an array that is returned within an array of Category from the getCategories() function is screwing me up somehow.
Note:
My segue between the CategoryTableViewController and the TopicsTableViewController was created on the storyboard by ctrl + dragging from the cell in CategoryTableViewController to the TopicsTableViewController.
Any help is greatly appreciate!
Thanks :)
This is difficult to answer without seeing the full view controllers. From viewing the code you have posted it seems that there is no relationship between the selected cell and the prepare for segue method. For example do you actually use the variable you create in the didSelectCell method? Looks like you didn't. In prepare for segue you just show the same thing over and over so the result is pretty obvious to be honest.
You need to store the index for the selected cell. Then show the corresponding data from your array using that index. Something like the below may work. Need to create a variable at class level called indexForCatergoryToShow.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
self.indexForCatergoryToShow = indexPath.row
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "fromCategorySegue")
{
let vc = segue.destinationViewController as! TopicsTableViewController
vc.categories = categories[indexForCatergoryToShow]
}
}
In your cell for row at indexPath:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.tag = indexPath.row
return cell
}
In your prepare for segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "fromCategorySegue") {
if let cell = sender as? UITableViewCell {
let row = cell.tag
// pass data to segue.destination
}
}
}
So you can know from which cell you are selecting.

Swift xCode 6.4 - using a variable generated by a tableview controller in a second view controller

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!

Swift tables click and pass information

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]
}

Resources