Swift dynamic view based on cell tapped in previous table view - ios

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.

Related

Passing value from Firebase from one tableView to another

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.

How to save a value from didSelectRowAtIndexPath and carry it to another tableView (SWIFT)

In my first table view I have an array which populates the table view. The user then clicks a cell. Each cell has a different text label. I want to carry the label value from one table view to the next, but when it gets to the other table view the variable I try to set it to is nil. I am using segues and have tried to use prepareForSeguge function. I just can't get the variable to save once it's left the didSelectRowatIndexPath method.
EDIT: I used an observer to check that my variable was being set, but it isn't set until after all other functions have run. How Would I then be able to use my variable in my second tableview to populate the table?
Here is my code:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow;
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
GenreSelector = currentCell.textLabel!.text
print(GenreSelector)
performSegueWithIdentifier("letsGo", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "letsGo") {
// initialize new view controller and cast it as your view controller
let viewController = segue.destinationViewController as! ResultTableViewController
// your new view controller should have property that will store passed value
viewController.GenreSelection = GenreSelector
}
}

how to display a new tableview from user selecting row in tableview swift

I am trying to figure how to segue to a new view when the user selects a certain row in the current tableview. I am thinking this will be done by the didselectrowatindexpath method but can not figure out the logic of how it will work. I would like it to display a view with the specific courses in the subject the user selected. I think this will use an array? I would appreciate any help here thanks.
Yes, you're right, you can do this be responding to didSelectRowAtIndexPath.
You can have a view controller as your table view delegate that implements these methods:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
if let thing = self.things.objectAtIndex(indexPath.row) as? Thing
{
self.performSegueWithIdentifier("OpenThing", sender: thing)
}
}
Where "OpenThing" is a segue defined in my storyboard.
Then I have overridden the prepareForSegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "OpenThing"
{
if let controller = segue.destinationViewController as? ThingViewController
{
if let thing = sender as? Thing
{
controller.thing = thing
}
}
}
}
This is a contrived example of having an array of "Things". I access a thing by row index then segue to the next view controller, providing the thing that I want to display.

prepareforsegue vs performwithsegue if statements.

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?

Swift: Make button trigger segue to new scene

Alright, so I have a TableView scene and I'm going to put a button in each of the cells and I need each cell to, when clicked, segue to its own ViewController scene. In other words, I need to know how to connect a button to a scene (The only button I have right now is "milk")
I know how to create an IBAction linked to a button, but what would I put in the IBAction?
I'm a beginner so I need a step-by-step explanation here. I've included a picture of my storyboard. I haven't written any code yet.
If you want to have a button trigger the segue transition, the easiest thing to do is Control+Click from the button to the view controller and choose a Segue option (like push). This will wire it up in IB for you.
If you want to write the code to do this yourself manually, you can do so by naming the segue (there's an identifier option which you can set once you've created it - you still need to create the segue in IB before you can do it) and then you can trigger it with this code:
V2
#IBAction func about(sender: AnyObject) {
performSegueWithIdentifier("about", sender: sender)
}
V3
#IBAction func about(_ sender: Any) {
performSegue(withIdentifier: "about", sender: sender)
}
You can use the delegation pattern. Presuming that you have implemented a custom table cell, you can define a property in its class to hold whatever you think is helpful to identify the row - it can be its index, or (my preferred way) an instance of a class which represents the data displayed in the cell (I'm calling it MyCellData.
The idea is to let the cell notify the table view controller about a tap on that button, passing relevant data about (the data displayed in) the row. The table view controller then launches a segue, and in the overridden prepareForSegue method it stores the data passed by the cell to the destination controller. This way if you have to display details data about the row, you have all the relevant info, such as the details data itself, or an identifier the destination view controller can use to retrieve the data for example from a local database or a remote service.
Define a protocol:
protocol MyCellDelegate {
func didTapMilk(data: MyCellData)
}
then declare a property named delegate in the cell class, and call its didTapMilk method from the IBAction
class MyTableCell : UITableViewCell {
var delegate: MyCellDelegate?
var data: MyCellData!
#IBAction func didTapMilk() {
if let delegate = self.delegate {
delegate.didTapMilk(self.data)
}
}
}
Next, implement the protocol in your table view controller, along with an override of prepareForSegue
extension MyTableViewController : MyCellDelegate {
func didTapMilk(data: MyCellData) {
performSegueWithIdentifier("mySegueId", sender: data)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "mySegueId" {
let vc: MyDestinationViewController = segue.destinationViewController as MyDestinationViewController
vc.data = sender as? MyCellData
}
}
}
Of course you need a data property on your destination view controller for that to work. As mentioned above, if what it does is displaying details about the row, you can embed all required data into your MyCellData class - or at least what you need to retrieve the data from any source (such as a local DB, a remote service, etc.).
Last, in cellForRowAtIndexPath, store the data in the cell and set its delegate property to self:
extension MyTableViewController : UITableViewDataSource {
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let data: MyCellData = retrieveDataForCell(indexPath.row) // Retrieve the data to pass to the cell
let cell = self.tableView.dequeueReusableCellWithIdentifier("myCellIdentifier") as MyTableCell
cell.data = data
cell.delegate = self
// ... other initializations
return cell
}
}
Use self.performSegueWithIdentifier("yourViewSegue", sender: sender) under your event for handling button's click:
#IBAction func redButtonClicked(sender: AnyObject) {
self.performSegueWithIdentifier("redView", sender: sender)
}
In the above code, redView is the segue identifier.

Resources