passing value from VC1 to VC2 - ios

I am now passing value from VC1 to VC2
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
FIRDatabase.database().reference().child("Menus/Day1").observeSingleEvent(of: .value, with: {(snap) in
if let snapDict = snap.value as? Dictionary <String, AnyObject>{
let date = snapDict["mealPic"] as! String
let OrderInfo = DataService.ds.REF_ORDER
let USERUID = FIRAuth.auth()!.currentUser!.uid
let userinfo = OrderInfo.child(date).child(USERUID).child("data")
self.valueToPass = date
}
})
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "ToVari") {
var Vari = segue.destination as! Variation
Vari.passedValue = valueToPass
}
}
and my VC2 viewDidLoad:-
var passedValue : String!
override func viewDidLoad() {
super.viewDidLoad()
MEALDATE.text = passedValue
// Do any additional setup after loading the view.
}
It actually worked but the weird thing is the "passedValue" in VC2 didn't show at first (I select cell in VC1 to performSegue to VC2)
I had to go back to VC1 and then tap the cell to VC2 again to let "passedValue" showing what it supposed to be there.
anyone know why is this happening ?

This might be due to call to Firebase that is async (not 100% sure). Also You are calling segue from storyboard so I would suggest following:
Remove segue from storyboard
in your response from Firebase, add following: self.performSegueWithIdentifier("ToVari", sender: self)
and you should be fine.

This is to do with the view controller life cycle. Simply put, when you perform a segue to another view controller, the app loads the view of the next view controller, then shows it. You need to keep this in mind when overriding prepareForSegue. At this point, the view of the next view controller has already been loaded, and in the case of a table, populated with what is essentially no data. To fix your problem, you simply need to tell the table to reload when the view appears. Just call tableView.reloadData() in viewWillAppear on your new view controller. :)

This is due to Firebase async call. You can follow #NickCatib solution or
func navigateToNextViewController(valueToPass: String) {
let variation = self.storyboard?.instantiateViewControllerWithIdentifier("Variation") as! Variation
variation.passedValue = valueToPass
self.navigationController?.pushViewController(variation, animated: true)
}
Call this function in Firebase async, pass value you want to it as
dispatch_async(dispatch_get_main_queue(), {() -> Void in
self.navigateToNextViewController(date)
})
Go to storyboard, select viewController, under 'identity inspector'->identity->storyboardId -> give the identifier. This should be same as it is given in above function. (ex, give identifier name same as viewController name).
Hope this will help you.

Make sure you perform segue after this line has been executed :
self.valueToPass = date
only then you can call(Swift 3):
performSegue(withIdentifier: "ToVari", sender: Self)

Just change the Method of tableview to:
func tableView(tableView: UITableView, willSelectRowAtIndexPath
indexPath: NSIndexPath) -> NSIndexPath? { //put your code here
}

Related

Passing Data Forward In Swift Without Segue

I'm currently making a to do list app using Swift 4. The home view controller has a tableview with some categories in it and when one is selected, it takes the user to a view controller where the items in that category are listed. I have a bug however as only the most recent item is showing in the list.
I think this is due to the way I am navigating to the list view controller. I am currently doing this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let destinationVC = ListVC()
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.selectedCategory = categoryArray[indexPath.row]
}
navigationController?.pushViewController(destinationVC, animated: true)
tableView.deselectRow(at: indexPath, animated: true)
}
And in the list view controller, I just have this to load the data:
var selectedCategory : Category? {
didSet {
loadItems()
}
}
I firstly created this app using storyboards and when using segues, it worked completely fine.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "goToItems", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as! TodoListVC
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.selectedCategory = categoryArray[indexPath.row]
}
}
So basically, the problem is that in the secondary list view controller, it will only show the most recently added item and no other ones even when they are stored in core data. I think it is to do with the way I am showing the secondary view controller as I am creating a new object every time.
How to properly go to the next view controller?
Remove the segue and add the storyboard id
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "storyboard_id") as! TodoListVC
vc.selectedCategory = categoryArray[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
Try this it will help you:-
You can send data from one view controller to another using storyboard
instance.
let next = self.storyboard?.instantiateViewController(withIdentifier: "NextControllerStoryBoard_id")as! NextController
next.str = "data which you want to pass"
self.navigationController?.pushViewController(next, animated: true)
here NextController is your controller class name where you want to go.str is the string name which you declare on NextController like
let str = String()
you are able to send string in that variable in same way you send any thing array dictionary ,image, Int value etc.
NextControllerStoryBoard_id is id which you declare at storyboard of that controller
In storybard id add your storybard id
Hope this will help you
I think that with this chunk of code I already sensed that you are passing data to the other view controller the incorrect way:
let destinationVC = ListVC()
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.selectedCategory = categoryArray[indexPath.row]
}
...
What I would suggest is that, instead of passing the data this way, you have to pass an array containing the items within the selected category using an array, then pass that array via the prepare for segue.
Then from the viewdidappear or viewdidload method in the receiving view controller, use the passed array from the source VC and use that as a datasource for your table view within that 2nd VC.

Passing data from a viewcontroller into tableviewCell

I am trying to get the Json data to show up in a table view cell, I have no value showing up. Please let me know what I am doing wrong. My tableview is linked Correctly to my viewcontroller(both as datasource and delegate).
Note: I havent called self.tableview.reloadData() anywhere as of now. If this is what needs to be done, Please tell me where I have to call it. I tried on viewdidload() it didnt work.
//json data
if let mydata = data {
do{
let myJson = try JSONSerialization.jsonObject(with: mydata, options: .mutableContainers) as AnyObject
if let articlesFromJson=myJson["account"] as! NSDictionary?{
self.points = articlesFromJson["Points__c"] as! Double
self.tier = articlesFromJson["Member_Tier__c"] as! String
//My destination VC is called HomeViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "HomeViewController" {
if let destVc = segue.destination as? HomeViewController {
destVc.pointrs = self.points
destVc.tiers = self.tier
}
}
}
//tableview
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! MemberInfoTableViewCell
cell.points.text = String(pointrs)
cell.tier.text = tiers
return cell
}
UPDATE : I just redid it, and it works. I must have missed something tiny! And The code seems to be correct. I also added a navigation controller so the segue code changed, nonetheless. It works. Thank you!
1) Make Sure your variable "pointrs" is initialized
2) you do not need to call table.relaod() when you are coming on the table view controller for the first time
3)make sure you have pass correct count in below delegate
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fruits.count //Array Count
}
Try this,, pass the values through a function to the "TableViewCellClass" you created and then , set the values of labels from there...
Make sure you indeed pass data into your table view controller because your table view controller looks okay. When you pass data, your code is
if segue.identifier == "HomeViewController" {
if let destVc = segue.destination as? HomeViewController {
destVc.pointrs = self.points
destVc.tiers = self.tier
}//Your code can ends up here
}//Your code can ends up here
See my comments from the code. If any of these if statements are false, you are not passing data. So first put a break point here to figure out if you are actually passing data or not.
If you are indeed passing data, put a break point in your cellForRow method to again make sure both your pointrs and tiers are valid with correct value

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.

Pass Data from UICollectionView in Swift 2

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

Load discrete view from table view?

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"

Resources