I have two table view controllers
InvoiceList view controller
InvoiceShow view controller
I use didSelectRowAtIndexPath method as bellow to get selected table cell specific value
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let rowObject = objects[indexPath.row]
let invoicehash = rowObject["hash_key"]!
}
i need to send invoicehash value to InvoiceShow controller when click the table cell of InvoiceList
i tried to use prepareForSegue function. but it is not applicable because it will trigger before the didSelectRawAtIndexPath function. so when i implemented it, gives the previous click event variable value. not correct one.
Please help me to access invoiceHash variable value from InvoiceShow controller
You will get the selected cell in prepareForSegue method itself.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let selectedIndexPath = self.tableView.indexPathForSelectedRow()!
let rowObject = objects[selectedIndexPath.row]
let invoiceHash = rowObject["hash_key"]!
let invoiceShowViewController = segue.destinationViewController as! InvoiceShowViewController
// Set invoiceHash to `InvoiceShowViewController ` here
invoiceShowViewController.invoiceHash = invoiceHash
}
You can still use a segue if you want and/or already setup on your storyboard.
You just need to connect the two view controllers in Interface Builder directly from one to another.
So, start ctrl-dragging from the controller itself and not from the TableViewCell (take a look at the screenshot)
then use the performSegueMethod with the new segue identifier like this:
self.performSegueWithIdentifier("mySegueIdentifier", sender: self)
and finally, your prepareForSegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "mySegueIdentifier" {
let selectedIndex = self.invoiceTableView.indexPathForSelectedRow
//if element exist
if selectedIndex?.row < myDataSourceArray.count {
let destination = segue.destinationViewController as! InvoiceShowViewController
let invoice = myDataSourceArray[selectedIndex!.row]
destination.invoice = invoice
}
}
}
That's it!
Related
I have View Controller A, which has five static collection view cells, with a title label, and a description label. Based on which cell was tapped, I need to segue to View Controller B, and View Controller B will present a list of products associated with that data.
I attempted to do this is didSelect method, but I think I am wrong... I realized after using print statements I am correctly getting the navigation to work, and I can also print the name label on View Controller A, but the data passed to View Controller B is nil.
View Controller A
var parameters: [Parameter] = [
Parameter(name: "Alkalinity", description: "A description here is about how important it is to have a stable measurement"),
Parameter(name: "Calcium", description: "A description here is about how important it is to have a stable measurement"),
// Cut the amount so I do not take too much space here
]
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selectedCell = parameters[indexPath.row]
// Create an instance of DeatailViewController and pass that variable
let destinationVC = DetailViewController()
destinationVC.dataReceived = selectedCell.name
self.performSegue(withIdentifier: "segueID", sender: self)
}
View Controller B
only a print statement.
Expected: Pass the name of the cell I tapped to the second VC, (For now) but I want to show a list of products associated with each element in name label. ex: Alkalinity will show Alkalinity products ( should I define this in the same of different model)?
Error:
Showing nil on VCB
Suggestions:
Maybe using index path in didSelectRow?
When using a segue to pass data you need to implement prepareForSegue
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "segueID", sender:parameters[indexPath.row])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueID" {
let vc = segue.destination as! DetailViewController
destinationVC.dataReceived = sender as! Model // Model is type of array parameters
}
}
but with vc instantiation DetailViewController() you need to use present/push
let destinationVC = DetailViewController()
destinationVC.dataReceived = selectedCell.name
self.present(destinationVC,animated:true)
For second way presenting DetailViewController() will crash the app as you don't load the vc from storyboard , so it should be like
let vc = self.storyboard!.instantiateViewController(withIdentifier: "DetailID") as! DetailViewController
If you are using segue, I would achieve that by doing something like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueID" {
if let destinationVC = segue.destination as? DetailViewController {
destinationVC.dataReceived = selectedCell.name
}
}
}
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.
My problem is I would like to Pass data from my collection view to a new view (tableview- but I think it's not necessary info)
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let myVC = DetailsTableViewController()
myVC.movieTitle = movies[indexPath.row].movieTitle!
print (movies[indexPath.row].movieTitle!)
performSegueWithIdentifier("DetailSegue", sender: reuseIdentifier)
}
Print is OK, but my movieTitle: String? will NIL on the DetailsViewController.
Help!
performSegueWithIdentifier will instantiate an appropriate destination controller and present it. The DetailsTableViewController you have instantiated here as myVC is never shown. You have a couple of options for how to approach this:
If you want to use segues then trigger the segue in didSelectItemAtIndexPath and implement prepareForSegue to pass data to the destination view controller (a destinationViewController will be available on the UIStoryboardSegue passed to that method).
Alternately you could avoid using segues and present your myVC directly by pushing it onto your current navigation controller (if one exists you could call self.navigationController.pushViewController(myVC, animated:true)), presenting it as a modal, or whatever makes sense in your app.
problem solved. thanks
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DetailSegue" {
let detailsVC = segue.destinationViewController as! DetailsTableViewController
if let cell = sender as? UICollectionViewCell, indexPath = collectionView!.indexPathForCell(cell) {
// use indexPath
detailsVC.movieTitle = movies[indexPath.row].movieTitle!
}
}
}
I know how to pass data using segues from prepareForSegue function, but the thing i have a TableViewCell from which there are two possible segues to two different ViewControllers (let's just say A, B as of now).
It was suggested here that it is best to connect the segues to View controller rather than the tableCell itself, which infact worked perfectly. But i want to pass information to the second View controller when the cell is clicked, So how to access segue that i connected to the Source ViewController.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showQuestionnaire"{
if let indexPath = self.tableView.indexPathForSelectedRow() {
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! QuestionnaireController
let patientQuestionnaire = patientQuestionnaires[indexPath.row] as! PatientQuestionnaire
controller.selectedQuestionnaire = patientQuestionnaire
self.performSegueWithIdentifier("showQuestionnaire", sender: self)
}
}
}
Again: This question is not regarding passing information through prepareForSegue
You should be using the didSelectRowAtIndexPath method to determine whether or not a cell was selected, and send the indexPath as the sender of the segue:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showQuestionnaire", sender: indexPath);
}
Then in your prepareForSegue method, get the indexPath from the sender parameter and use that to pass the correct row/data:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "showQuestionnaire") {
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! QuestionnaireController
let row = (sender as! NSIndexPath).row; //we know that sender is an NSIndexPath here.
let patientQuestionnaire = patientQuestionnaires[row] as! PatientQuestionnaire
controller.selectedQuestionnaire = patientQuestionnaire
}
}
To explain...
I used the index path as the sender so I can easily pass the index path. You could also check for the currently selected cell using other UITableView methods, but I've always done it this way with success
You can't put performSegueWithIdentifier within the prepare for segue method, because performSegueWithIdentifier leads to prepareForSegue; You are just looping around and around with no aim. (When you want to perform a segue, prepareForSegue is always executed)
prepareForSegue doesn't run by itself when a row is selected. This is where you need didSelectRowAtIndexPath. You need a performSegueWithIdentifier outside of the method as described previously, which should be in didSelectRowAtIndexPath
So I have a table view that I want to segue to specific views when a specific cell is selected. For example, if the cell at index 0 is selected, I want the "RedViewController" to be visible.
The example I keep receiving looks something like this (located in the VC with the table view)
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let destination = segue.destinationViewController as? RedViewController {
if let blogIndex = tableView.indexPathForSelectedRow()?.row {
destination.blogName = swiftBlogs[blogIndex]
}
}
}
}
(Where blogName and swiftBlogs are random examples)
But this just loads specific data into a singular view controller. Preferably I want a switch statement for each index path that makes a specific VC visible.
Ok, so write your code that way. Don't link your table views directly with a segue. Instead write code in your didSelectRowAtIndexPath.
In that method you can write a switch statement, or use an array lookup, to load a view controller using a unique ID and the instantiateViewControllerWithIdentifier, or trigger a through code using performSegueWithIdentifier.
I figured it out thanks to Duncan C and a little more research!
In the table view VC I added the handy function
func switchToViewController(identifier: String) {
let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(identifier) as! UIViewController
self.navigationController?.setViewControllers([viewController], animated: false)
}
And in the didselectRowAtIndexPath
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedRow = indexPath.indexAtPosition(indexPath.row)
switch selectedRow {
case 0:
switchToViewController("RedVCIdentifier")
default:
println("Unknown Cell selected")
}
}
But also had to add a Storyboard ID to the RedViewController in the storyboard as "RedVCIdentifier"