0

I am making an app which has a news feed of images (HomeViewController). The user can tap on each image which segues to the SiteViewController which has a table view of empty data and a button that when clicked segues to ContextSheetViewController 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 (siteCodeTextView, areaCodeTextView, trenchTextView) is saved to firebase and it dismisses back to the SiteViewController. I then want to retrieve the data value of siteCodeTextView 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: Unexpectedly found nil while unwrapping an Optional value occurs. And my sheetId is printing nil in SiteViewController so I am not sure how to retrieve it correctly? Any help?

Here is my storyboard of relevant view controllers:

enter image description here

Code for SiteViewController:

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 () -> 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) -> Int { return sheets.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> 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 for ContextSheetViewController:

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 for SiteTableViewCell:

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") } } 

enter image description here

1
  • When you print do you see data from firebase? Commented Jun 27, 2018 at 9:54

1 Answer 1

1

From what you have shown the culprit is the postId, you are using it to fetch data from Firebase and yet you haven't shown anywhere what its value is. When the user taps on an image, the postId is not transfered to the SiteViewController.

In the SiteViewController remove the ! and replace it with ?, put an initializer that will take the postID as a parameter.

var postId:String? func initPost(forImage postId: String) { self.postId=postId } 

In the previous news feed VC inside the segue or didSelectForRow(i don't know what you use for transition, initialize the SiteViewController, so when it is presented it knows which ID to retrieve data for.

Another thing that needs mentioning is that you are using observe but you are not removing the observers.

EDIT: this answer was based on me not knowing what your HomeVC looked like.

 if segue.identifier == "SiteSegue" { let siteVC = segue.destination as! SiteViewController let postId = sender as! String siteVC.postId = postId } 
Sign up to request clarification or add additional context in comments.

10 Comments

Thanks for your help! I'm relatively new to swift so I'm not sure how to put an initializer that will take postID as a parameter. I've edited my question and added in my previous VC (news feed) to show my code inside the segue as it is retrieving the post.id from there
Ok i edited my question to show you how to put an initializer in your VC. But after seeing your edit, another way to do it is yours except you haven't set your news feed VC as the delegate of the SiteViewController.
I have edited my post, but the big question here is why are you using segue and not didSelectRowAt??
I've included the line of code that I was missing, but the error: "Value of type 'SiteViewController' has no member 'delegate', appears?
Delete that line, now it should work as i have tested it on my end, implement everything else though and let me know..
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.