I have a table view populated with cells containing the user's friends. A cell, when selected, should pull up that friend's profile. However, while the profile view does show up, I don't know how to tell its view controller to load that friend's profile data. How do you have two view controllers communicate with each other in response to user action? Thanks in advance.
Let's have two view controllers:
destinationVC and sourceVC
Create optional variables in destinationVC to store values which you want to share between the VC's.
In the sourceVC
override prepareForSegue method
obtain the destinationVC using segue.destinationViewController and store the returned value in a variable, say destVC
initialise the optional variables of destVC with values from selected cell
you can obtain the selected cell by using tableview.cellForRowAtIndexPath(tableView.indexPathForSelectedRow())
get data from selected cell and assign it to destVC's variables
Then in the destVC
In the viewDidLoad method
Check if the optional variables are not nil
Use the values of variables to load/update the destVC.
Edit: Updated answer according to Mike Taverne's comment.
You need to set the "user" property of that "destination" view controller in your current view controller:
Set a selectedUser property in your current view controller:
class CurrentTableViewController: TableViewController {
var selectedUser: AnyObject?
...
}
Then when that friend's cell is selected, set the "selectedUser" property in "didSelectRowAtIndexPath":
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedUser = // get the user property depending on how you're defining your table cells in the first place
self.performSegueWithIdentifier("pushToUser", sender: self)
}
Next in your prepareForSegue method, define the destination view controller and set its "user" property from the "self.selectedUser" property:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "pushToUser") {
var userProfileTableViewController: UserProfileTableViewController = segue.destinationViewController as UserProfileTableViewController
userProfileTableViewController.user = self.selectedUser
}
}
Last, in the destination view controller (which in this case is UserProfileTableViewController) you can call your database queries, etc. using "self.user".
Related
I am trying to pass value I get from Firebase to another tableView. I get 2 values from Firebase - "Brands" and "Products". I am trying to make like car app. If you click on Ford then new tableView will appear and shows all the Ford models. This is what I've done so far.
like this I get Brands from Firebase:
func parseSnusBrands(){
let ref = FIRDatabase.database().reference().child("Snuses").child("Brands")
ref.observeSingleEventOfType(.Value, withBlock: { (snapshot) in
if snapshot.exists() {
if let all = (snapshot.value?.allKeys)! as? [String]{
for a in all{
if let products = snapshot.value![a] as? [[String:String]]{
self.snusBrandsArray.append(["key":a,"value":products])
}
}
self.snusBrandsTableView.reloadData()
}
}
})
}
And like this I detect which cell is clicked and print the product that belongs to the clicked Brand:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
print("products at \(indexPath.row) --> \(snusBrandsArray[indexPath.row]["value"])")
}
How to pass the (snusBrandsArray[indexPath.row]["value"]) to new tableView? I tried using segues and looking for tutorials like "How to pas value between viewControllers" but I am out of luck. Right now I have 2 tableViewController.swift files and one tableViewCustomCell.swift file. Do I need some more files?
For send data, first of all declare your variable in 2nd view controller..
var productsValue = [[String:String]]()
and in 1st viewcontroller
var valueTopass = [[String:String]]()
Than in didSelectRowAtIndexPath, take a value in one valueTopass
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("products at \(indexPath.row) --> \(snusBrandsArray[indexPath.row]["value"])")
if let products = snusBrandsArray[indexPath.row]["value"] as? [[String:String]]{
valueTopass = products
performSegueWithIdentifier("toProducts", sender: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if (segue.identifier == "toProducts") {
var viewController = segue.destinationViewController as! SnusProductsTableViewController
viewController.productsValue = valueTopass
print(productValues)
}
}
You need to use Segues to pass the data forward.
To pass data from the current view controller to the next new view controller using segues, first create a segue with an identifier in the relevant storyboard. Override your current view controller's prepareForSegue method. Inside the method check for the segue you just created by its identifier. Cast the destination view controller and pass data to it by setting properties on the downcast view controller.
Setting an identifier for a segue:
Segues can be performed programatically or using button action event set in the storyboard by ctrl+drag to destination view controller.
You can call for a segue programatically, when needed, using segue identifier in the view controller:
func showDetail() {
performSegueWithIdentifier("showDetailingSegue", sender: self)
}
You can configure segue payload in the override version of prepareForSegue method. You can set required properties before destination view controller is loaded.
Swift
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetailingSegue" {
let controller = segue.destinationViewController as! DetailViewController
controller.isDetailingEnabled = true
}
}
DetailViewController is the name of the second view controller and isDetailingEnabled is a public variable in that view controller.
To expand on this pattern, you can treat a public method on DetailViewController as a pseudo initializer, to help initialize any required variables. This will self document variables that need to be set on DetailViewController without having to read through it's source code. It's also a handy place to put defaults.
Swift
func initVC(isDetailingEnabled: Bool) {
self.isDetailingEnabled = isDetailingEnabled
}
Why not pass the whole dictionary with all the contents from firebase to the new VC using prepare for segue?
And then store the dict in the destinationVC data model?
That should do the trick.
I have a table view with a list of events. I now am trying to create a dynamic view that can show details about all of those events based on the event tapped on. Two questions I have are how do I create a generic segue that I can use for any table cell to go to the same view, and then in that view how do I access the cell that brought the user to the view?
You would use didSelectRowAtIndexPath. First, create a variable eventToPass of type Event (or whatever your class is called) on your ViewController. Then, you should get the object that represents your data, then pass that to your new UIViewController. Something like:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let event = eventsArray[indexPath.row]
self.eventToPass = event
self.performSegueWithIdentifier("EventSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "EventSegue") {
var detailVC = segue.destinationViewController as EventDetailViewController
detailVC.event = eventToPass
}
}
This assumes that you have a ViewController called EventDetailViewController that has a property called event. From here, you can access any of the event's details on your new ViewController.
I am still trying to make sense of this idea myself so if I am unclear I apologize. If there are more questions please ask instead of down voting.
Im my app I have a tableview populated with restaurant names that I am querying from parse. What I want to do is: when the user clicks on a cell I want to have have the cell segue to a tableView populated with that restaurants menu.
Now, my question is:
1. How can I have the segue identify the parse ID of the restaurant selected at the indexPath and have this ID input into the query for the appropriate menu in the parse database.
You can use prepareForSegue to get a reference to the view controller you're passing the information to, and set that info before you segue to it, so that your new view controller has the appropriate Parse object. As well as a reference to the new view controller, you can also get a reference to the index path that was selected, and use your data source to pass the information along.
When user clicks on a particular row of tableView, didSelectRowAtIndexPath will be triggered. So, you can get the name of the restaurant user clicked by getting the element at index path. See ex below.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let index = self.tableView.indexPathForSelectedRow?.row
//assuming listOfRestaurants is your list of restaurants
let restaurantName = listOfRestaurants[index!] as String
//now you can query the database with the restaurantName to get details
//once you get the details Object
performSegueWithIdentifier(segueId!, sender: self)
//here segueId is the name of your segue identifier
}
//later in your prepareForSegue method pass the data you retrieved from database to the new View controller. Ex follows.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//considering restaurantDetailsSegue as your segue id
if (segue.identifier == "restaurantDetailsSegue") {
let NVC: newViewController = segue.destinationViewController as! newViewController
NVC.details = details
}
}
Hope it helps.
Suppose I have a table view, how would i go about creating code to have one cell go to one view controller and then have another cell to a second view controller. Specifically the prepare for segue and perform with segue if statements.
Your parent view controller (where the table view lives) should have your UITableViewDelegate methods.
You'll need to create your own implementation of:
optional func tableView(_ tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath)
And in there (which gets called when a cell is pressed), you'll want to call
self.performSegueWithIdentifier("Load View", sender: self)
One of the parameters passed into didSelectRowAtIndexPath is the index path row, so you know which row the user pressed. And you can pass along that cell (or the information, or the object that the cell is drawing it's contents from) in the "sender" parameter of the performSegueWithIdentifier method.
You'll have direct access to the child view controller from the parent in the prepareForSegue:sender: method. So you can do something like:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "Load View") {
// pass data to next view
let cellData = sender as YourDataObject
let childViewController = segue.destinationViewController as YourChildViewController
// and now you can directly set whatever custom fields / bits
// you need to set in your destination view controller
}
}
Makes sense so far?
I have a UITableView which I have set up to go to a different VC when a row is selected by the user (the table only consists of one array). I want to pass the row index of the selected item. I am using didSelectRowAtIndexPath to set a variable named selectedCellIndex to the row index. However, since I also have the tableView set up to go to the next VC prepareForSegue fires off (or around the same time) as didSelectRowAtIndexPath. As a result the first time I select an item from the list the value sent is nil, after that I always get the previous value of the row selected. Any Ideas on how to make sure that the variable is set before the app transitions to the next segue without putting a pause?
Here is my code:
var selectedCellIndex:Int!
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
var indexPath = tableView.indexPathForSelectedRow() as NSIndexPath?
selectedCellIndex = indexPath?.row as Int?
}
//SEGUE
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "signature" {
let vc = segue.destinationViewController as SignatureViewController
vc.index = "\(selectedCellIndex)"
}
}
Thanks
You can get the selected index path from the table view directly using the indexPathForSelectedRow method. There is no need to implement didSelectRowAtIndexPath just to store the selected index.
The prepareForSegue: method is the only method where you should set/access variables that are necessary for a transition.