Pass Firebase data from UITableViewCell to ViewController

Viewed 49

First post so apologies for anything I do wrong here.

I've been stuck on this for awhile now. I think the problem is pretty straight forward, but I seem to be missing something. The code below is from my homeVC which has a tableview. I created a tableViewCell as well. I have firebase hooked up and the data saves properly. Overall goal is to create a recipe manager. Home screen has a list of recipes, you can add and edit. When you click on the recipe name in the homeVC table you are taken to ShowDataVC. I am able to load the recipe name into the tableview but cant seem to get it to load when selected to the ShowDataVC. Ultimately I think I want to be able to use the UUID I created for each recipe to display all info, handling edits, handling error state if no recipe is found for that ID. Thanks in advance!

struct RecipeData {

let user: String
let recipeName: String
let ingredientsText: String?
let directionsText: String?
let servingsNumber: Int?
let id = UUID().uuidString

}

import UIKit
import Firebase

class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    @IBOutlet weak var table: UITableView!
    @IBOutlet weak var logout: UIBarButtonItem!
    @IBOutlet weak var add: UIBarButtonItem!
    
    let db = Firestore.firestore()
    
    var id = UUID().uuidString
    
    var data = [RecipeData]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .gray
        table.delegate = self
        table.dataSource = self
        navigationItem.hidesBackButton = true
        
        table.register(UINib(nibName: D.cellNibName, bundle: nil), forCellReuseIdentifier: D.cellIdentifier)
        loadRecipeNames()
        
    }
    
    func loadRecipeNames() {
        
        db.collection(D.FStore.collectionName)
            .addSnapshotListener { (querySnapshot, err) in
                if let err = err {
                    print("Error getting documents: \(err)")
                } else {
                    for document in querySnapshot!.documents {
                        let data = document.data()
                        if let user = data[D.FStore.userField] as? String,
                           let recipeNameLabels = data[D.FStore.recipeTextField] as? String {
                            
                            //print("This is = \(document.documentID) => \(document.data())")
                            
                            let newRecipe = RecipeData(user: user, recipeName: recipeNameLabels, ingredientsText: nil, directionsText: nil, servingsNumber: nil)
                            self.data.append(newRecipe)
                            
                            DispatchQueue.main.async {
                                self.table.reloadData()
                                
                                let indexPath = IndexPath(row: self.data.count - 1, section: 0)
                                self.table.scrollToRow(at: indexPath, at: .top, animated: true)
                                
                            }
                            
                        }
                    }
                    
                }
            }
    }
    
    @IBAction func logoutPressed(_ sender: UIBarButtonItem) {
        do {
            try Auth.auth().signOut()
            navigationController?.popToRootViewController(animated: true)
            
        } catch let signOutError as NSError {
            print("Error signing out: %@", signOutError)
        }
    }
    
    @IBAction func addPressed(_ sender: UIBarButtonItem) {
        let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: D.addRecipeSegue) as! AddRecipeViewController
        navigationController?.pushViewController(vc, animated: true)
        
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let data = data[indexPath.row]
        
        let cell = table.dequeueReusableCell(withIdentifier: D.cellIdentifier, for: indexPath) as! RecipeNameCell
        
        cell.label.text = data.recipeName
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "ShowSegue", sender: self)
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "ShowSegue" {
            
            if let indexPath = table.indexPathForSelectedRow {
                let vc = segue.destination as! ShowRecipeDataViewController
                vc.newData = data[indexPath.row]
            }
        }
        
    }
    
}
import UIKit
import Firebase

class AddRecipeViewController: UIViewController, UIImagePickerControllerDelegate & UINavigationControllerDelegate {
    
    @IBOutlet weak var recipeNameTextField: UITextField!
    @IBOutlet weak var ingredientsTextField: UITextView!
    @IBOutlet weak var directionsTextField: UITextView!
    @IBOutlet weak var stepper: UIStepper!
    @IBOutlet weak var numServingLabel: UILabel!
    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var takePicture: UIButton!
    @IBOutlet weak var saveButton: UIBarButtonItem!
    
    let db = Firestore.firestore()
    
    var data: [RecipeData] = []
    
    var stepperValue: Int = 0
    var id = UUID().uuidString
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .lightGray
        
    }
    
    @IBAction func savePressed(_ sender: UIBarButtonItem) {
        if let text = recipeNameTextField.text, !text.isEmpty {
            saveData(text: text)
            print("Data successfully saved!")
        }
        
    }
    
    func saveData(text: String) {
        if let recipeName = recipeNameTextField.text,
            let addedIngredients = ingredientsTextField.text,
            let directionsText = directionsTextField.text,
            let servingsNum = numServingLabel.text,
           
            let user = Auth.auth().currentUser?.email {
            
            let newRecipeRef = db.collection(D.FStore.collectionName).document(id)
            newRecipeRef.setData([
                D.FStore.recipeTextField: recipeName,
                D.FStore.ingredientsText: addedIngredients,
                D.FStore.directionsText: directionsText,
                D.FStore.numberServings: servingsNum,
                D.FStore.userField: user,
                D.FStore.id: id
            ]) { err in
                if let err = err {
                    print("Error adding document: \(err)")
                } else {
                    print("Document added with ID:\(newRecipeRef)")
                }
            }
        }
    }
    
    @IBAction func takePicturePressed(_ sender: UIButton) {
        let picker = UIImagePickerController()
        picker.sourceType = .camera
        picker.delegate = self
        picker.allowsEditing = true
        present(picker, animated: true, completion: nil)
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true, completion: nil)
        guard let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
            return
        }
        guard let imageData = image.pngData() else {
            return
        }
        
    }
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }
    
    @IBAction func stepperPressed(_ sender: UIStepper) {
        stepperValue = Int(sender.value)
        numServingLabel.text = "\(stepperValue)"
    }
    
}

import UIKit
import Firebase

class ShowRecipeDataViewController: UIViewController {
    
    @IBOutlet weak var recipeNameLabel: UILabel!
    @IBOutlet weak var ingredientsText: UILabel!
    @IBOutlet weak var directionsText: UILabel!
    @IBOutlet weak var numServings: UILabel!
    @IBOutlet weak var logout: UIBarButtonItem!
    
    let db = Firestore.firestore()

    var newData = [RecipeData]()
    
    var data: [RecipeData] = []
    
    var id = UUID().uuidString
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemOrange

    }
    

    @IBAction func logoutPressed() {
        do {
            try Auth.auth().signOut()
            navigationController?.popToRootViewController(animated: true)
            
        } catch let signOutError as NSError {
            print("Error signing out: %@", signOutError)
        }
    }
}

1 Answers

Update

You'll need to assign the values to your outlets. You can do that like so.

class ShowRecipeDataViewController: UIViewController {
    
    @IBOutlet weak var recipeNameLabel: UILabel!
    @IBOutlet weak var ingredientsText: UILabel!
    @IBOutlet weak var directionsText: UILabel!
    @IBOutlet weak var numServings: UILabel!
    @IBOutlet weak var logout: UIBarButtonItem!
    
    let db = Firestore.firestore()

    var newData: RecipeData? = nil
    
    var data: [RecipeData] = []
    
    var id = UUID().uuidString
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemOrange
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        guard let newData = newData else {
            return
        }
        recipeNameLabel.text = newData.recipeName
        ingredientsText.text = newData.ingredientsText
        directionsText.text = newData.directionsText
        numServings.text = "\(newData.servingsNumber)"
    }
    

    @IBAction func logoutPressed() {
        do {
            try Auth.auth().signOut()
            navigationController?.popToRootViewController(animated: true)
            
        } catch let signOutError as NSError {
            print("Error signing out: %@", signOutError)
        }
    }
}

Original Answer

You'll need to share your ShowRecipeDataViewController code to get a better answer. But, the problem is probably there. But if I had to guess you'll need to add the code to tell the textField or Label to have the data in it.

Often, people do that in the ViewDidLoad function like:

// inside ShowRecipeDataViewController
override func viewDidLoad() {
    super.viewDidLoad()
    recipeLabel.text = data.recipeName
    ingredientsTextField.text = data.ingredients
}
// etc.,
Related