title: Swift: Retrieve data from Firebase and display in table view
body: <p>I am making an app which has a news feed of images (HomeViewController). The user can tap on each image which segues to the <strong>SiteViewController</strong> which has a table view of empty data and a button that when clicked segues to <strong>ContextSheetViewController</strong> where the user can upload data of the image that they clicked on in the news feed. The user then presses upload and this data (<strong>siteCodeTextView</strong>, areaCodeTextView, trenchTextView) is saved to firebase and it dismisses back to the SiteViewController. I then want to retrieve the data value of <strong>siteCodeTextView</strong> that has just been uploaded of the image in the table view of the SiteViewController. But when I press upload in the ContextSheetViewController the error: <strong>Unexpectedly found nil while unwrapping an Optional value</strong> occurs. And my <strong>sheetId</strong> is printing nil in SiteViewController so I am not sure how to retrieve it correctly? Any help? </p>
  
  <p>Here is my storyboard of relevant view controllers:</p>
  
  <p><a href="https://i.stack.imgur.com/xeiiz.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/xeiiz.png" alt="enter image description here"></a></p>
  
  <p>Code for SiteViewController: </p>
  
  <pre><code>class SiteViewController: UIViewController {
  
      @IBOutlet weak var tableView: UITableView!
  
  
      var sheets = [Sheet]()
      var users = [User]()
      var sheetId: String!
  
      var postId: String!
  
      override func viewDidLoad() {
          super.viewDidLoad()
  
          tableView.dataSource = self
          loadSheets()
  
          print(postId)
          print(sheetId)
      }
      func loadSheets() {
          Api.Sheet.REF_SHEETS.child(self.postId!).observe(.childAdded, with: {
              snapshot in
              Api.Sheet.observeSheets(withSheetId: snapshot.key, completion: {
                  sheet in
  //                self.fetchUser(uid: sheet.uid!, completed: {
                      print("sheet id: \(sheet.id)")
                      print("sheet uid: \(sheet.uid)")
                  self.sheets.append(sheet)
                  self.tableView.reloadData()
  //                })
              })
          })
      }
  
      func fetchUser(uid: String, completed:  @escaping () -&gt; Void ) {
  
          Api.User.observeUser(withId: uid, completion: {
              user in
              self.users.append(user)
              completed()
          })
      }
  
      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
          if segue.identifier == "SheetSegue" {
              let sheetVC = segue.destination as! SheetViewController
              let sheetId = sender as! String
              sheetVC.sheetId = sheetId
  
          }
      }
  }
  
  extension SiteViewController: UITableViewDataSource {
      func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
          return sheets.count
      }
      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
          let cell = tableView.dequeueReusableCell(withIdentifier: "SheetCell", for: indexPath) as! SiteTableViewCell
          let sheet = sheets[indexPath.row]
  
          print("sheet id: \(sheet.id)")
          print("sheet uid: \(sheet.uid)")
  //        let user = users[indexPath.row]
  //        cell.user = user
          cell.sheet = sheet
          cell.delegate = self
          return cell
      }
  }
  
  extension SiteViewController: SiteTableViewCellDelegate {
      func goToSheetVC(sheetId: String) {
          performSegue(withIdentifier: "SheetSegue", sender: sheetId)
  
      }
  }
  </code></pre>
  
  <p>Code for ContextSheetViewController: </p>
  
  <pre><code>class ContextSheetViewController: UIViewController {
  
  
      @IBOutlet weak var siteCodeTextView: UITextField!
      @IBOutlet weak var areaCodeTextView: UITextField!
      @IBOutlet weak var trenchTextView: UITextField!
      @IBOutlet weak var uploadArtefactImage: UIImageView!
  
      @IBOutlet weak var artefactImageView: UIImageView!
  
      var selectedImage: UIImage?
      var postId: String!
      override func viewDidLoad() {
          super.viewDidLoad()
          let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.handleSelectPhoto))
          uploadArtefactImage.addGestureRecognizer(tapGesture)
          uploadArtefactImage.isUserInteractionEnabled = true
  
      }
  
      @objc func handleSelectPhoto() {
          let pickerController = UIImagePickerController()
          pickerController.delegate = self
          present(pickerController, animated: true, completion: nil)
      }
  
      @IBAction func uploadButton_TouchUpInside(_sender: Any) {
  
          if let profileImg = self.artefactImageView.image, let imageData = UIImageJPEGRepresentation(profileImg, 0.1) {
              let photoIdString = NSUUID().uuidString
              print(photoIdString)
              let storageRef = Storage.storage().reference(forURL: Config.STORAGE_ROOF_REF).child("sheets").child(photoIdString)
              storageRef.putData(imageData, metadata: nil, completion: { (metadata, error) in
                  if error != nil {
                      ProgressHUD.showError(error!.localizedDescription)
                      return
                  }
                  let photoUrl = metadata?.downloadURL()?.absoluteString
                  self.sendDataToDatabase(photoUrl: photoUrl!)
              })
          } else {
              ProgressHUD.showError("Sheet Image can not be empty!")
          }
      }
  
      func sendDataToDatabase(photoUrl: String) {
  //        let ref = Database.database().reference()
          let sheetsReference = Api.Sheet.REF_SHEETS
  //        let sheetsReference = ref.child("sheets")
          let newSheetId = sheetsReference.childByAutoId().key
          let newSheetReference = sheetsReference.child(newSheetId)
          guard let currentUser = Auth.auth().currentUser else {
              return
          }
          let currentUserId = currentUser.uid
          newSheetReference.setValue(["uid": currentUserId, "photoUrl": photoUrl, "siteCodeTextView": siteCodeTextView.text!, "areaCodeTextView": areaCodeTextView.text!, "trenchTextView": trenchTextView.text!], withCompletionBlock: {
              (error, ref) in
              if error != nil {
                  ProgressHUD.showError(error!.localizedDescription)
                  return
          }
              let postSheetRef = Api.Sheet.REF_SHEETS.child(self.postId!).child(newSheetId)
  //            let postSheetRef = Api.Sheet.REF_SHEETS.child("post-sheets").child(self.postId).child(newSheetId)
              postSheetRef.setValue(true, withCompletionBlock: { (error, ref) in
                  if error != nil {
                      ProgressHUD.showError(error!.localizedDescription)
                      return
                  }
              })
  
  
              ProgressHUD.showSuccess("Success")
              self.clean()
              self.navigationController?.popViewController(animated: true)
          })
      }
  
      func clean() {
          self.siteCodeTextView.text = ""
          self.uploadArtefactImage.image = UIImage(named: "upload")
          self.artefactImageView.image = UIImage(named: "image")
      }
  }
  
  extension ContextSheetViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
      func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
          print("did Finish Picking Media")
          if let image = info["UIImagePickerControllerOriginalImage"] as? UIImage{
              artefactImageView.image = image
  //            selectedImage = image
  //            uploadArtefactImage.image = image
          }
          dismiss(animated: true, completion: nil)
      }
  }
  </code></pre>
  
  <p>Code for SiteTableViewCell: </p>
  
  <pre><code>protocol SiteTableViewCellDelegate {
      func goToSheetVC(sheetId: String)
  
  }
  
  class SiteTableViewCell: UITableViewCell {
  
  
      @IBOutlet weak var profileImageView: UIImageView!
      @IBOutlet weak var siteSheetLabel: UILabel!
      @IBOutlet weak var nameLabel: UILabel!
  
      var delegate: SiteTableViewCellDelegate?
  
      var sheet: Sheet? {
          didSet {
              updateView()
          }
      }
  
      var user: User? {
          didSet {
              setupUserInfo()
          }
      }
  
      func updateView() {
          siteSheetLabel.text = sheet?.siteCodeTextView
  
      }
  
  
      override func awakeFromNib() {
          super.awakeFromNib()
          // Initialization code
      }
  
      func setupUserInfo() {
          nameLabel.text = user?.username
          if let photoUrlString = user?.profileImageUrl {
              let photoUrl = URL(string: photoUrlString)
              profileImageView.sd_setImage(with: photoUrl, placeholderImage: UIImage(named: "placeholderImg"))
          }
      }
  
  
      override func setSelected(_ selected: Bool, animated: Bool) {
          super.setSelected(selected, animated: animated)
          let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.siteSheetLabel_TouchUpInside))
          siteSheetLabel.addGestureRecognizer(tapGesture)
          siteSheetLabel.isUserInteractionEnabled = true
      }
  
      @objc func siteSheetLabel_TouchUpInside() {
  
          print(sheet?.id)
  
          if let id = sheet?.id{
              delegate?.goToSheetVC(sheetId: id)
          }
      }
      override func prepareForReuse() {
          super.prepareForReuse()
          profileImageView.image = UIImage(named: "placeholderImg")
      }
  
  }
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/xeiiz.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/xeiiz.png" alt="enter image description here"></a></p>