I am new to coding and have been trying to figure out the current problem I have for the last few weeks.
I have posted a bunch asking different variations of the same question and was informed the way I was trying to execute my idea was incorrect.
I am trying to send a collection of data to a list of users. The data involves a company name, the company's image, the day they need to make a decision and the day it was sent. I am currently able to send that information to my firebase database and firebase storage for the company image. The company image is also stored as a string under the company's information node.
What I was originally trying to accomplish was being able to create cells by pushing a button. The table would populate a cell with four textfields. A name textfield would be where I selected the user. Their firebase database name would show up in the textfield. I then could input text in three other textfields that corresponded to only that user. The user would be able to see the company info and the dates but then only their specific row data. I was told that I shouldn't be doing that and I decided to venture off to another possible solution.
Situation Now:
I have the same view controller set up with the company information and add button. That looks like:
When the add button is pressed, a new view controller is shown with four textfields. The view controller name textfield allows for the user to select a user from the database and the text changes to that persons name. It looks like this:
I am using the name textfield to append an array which then is being used for the table in the first view controller to determine the number of rows. It is currently appending the array but not populating any cells. I plan on using labels to save the user and the other 3 textfields to the same row. But I can't even get any cells to populate.
Here is the code for the view controller that will display the users and their info in the table below the company information:
import UIKit
import Firebase
class ConsiderationsTestViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var tableView: UITableView!
static var numberOfPeople: [String] = []
var AddPersonCell = "AddPersonCell"
@IBOutlet weak var CompanyImage: UIImageView!
@IBOutlet weak var companyNameTextFieldConsiderations: UITextField!
@IBOutlet weak var companyDescriptionTextFieldConsiderations: UITextField!
@IBOutlet weak var startDateTextFieldConsiderations: UITextField!
@IBOutlet weak var endDateTextFieldConsiderations: UITextField!
let datePickerS = UIDatePicker()
let datePickerE = UIDatePicker()
var database: Database!
var storage: Storage!
var selectedImage: UIImage?
var ref:DatabaseReference?
var databaseHandle:DatabaseHandle = 0
let dbref = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.companyNameTextFieldConsiderations.delegate = self
self.companyDescriptionTextFieldConsiderations.delegate = self
// Set the Firebase reference
ref = Database.database().reference()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ConsiderationsTestViewController.handleSelectCompanyImageView))
CompanyImage.addGestureRecognizer(tapGesture)
CompanyImage.isUserInteractionEnabled = true
self.navigationController!.navigationBar.isTranslucent = false
navigationItem.backBarButtonItem = UIBarButtonItem(
title: "", style: .plain, target: nil, action: nil)
createDatePickerForStart()
createDatePickerForEnd()
}
@objc func handleSelectCompanyImageView() {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.allowsEditing = true
present(pickerController, animated: true, completion: nil)
}
@IBAction func AddPersonTapped(_ sender: Any) {
}
@IBAction func sendButtonTapped(_ sender: Any) {
let companyNameC = companyNameTextFieldConsiderations.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let companyDescriptionC = companyDescriptionTextFieldConsiderations.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let today = Date()
let formatter1 = DateFormatter()
formatter1.dateFormat = "MMM d y"
print(formatter1.string(from: today))
let todaysDate = formatter1.string(from: today)
let storageRef = Storage.storage().reference(forURL: " MY STORAGE URL HERE")
let imageName = companyNameTextFieldConsiderations.text!
let storageCompanyRef = storageRef.child("Company_Image_Considerations").child("\(todaysDate)").child(imageName)
let companyDescriptionTextFieldText = companyDescriptionTextFieldConsiderations.text
let dateToStart = startDateTextFieldConsiderations.text
let dateToDecide = endDateTextFieldConsiderations.text
let companyRef = Database.database().reference().child("Considerations").child("\(todaysDate)").child(imageName)
let index = IndexPath(row: 0,section: 0)
let cell = tableView.cellForRow(at:index) as! ConsiderationsCell
let nameTFC = cell.nameTextFieldConsiderations.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let feedTFC = cell.feedTextFieldConsiderations.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let storyTFC = cell.storyTextFieldConsiderations.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let compensationTFC = cell.compensationTextFieldConsiderations.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let values = ["Feed_Quantity": feedTFC, "Story_Quantity": storyTFC, "Compensation": compensationTFC]
let considerationInfluencerRef = Database.database().reference().child("Considerations").child("\(todaysDate)").child(imageName).child("Users").child("\(nameTFC)")
guard let imageSelected = self.CompanyImage.image else {
print ("Avatar is nil")
return
}
var dict: Dictionary<String, Any> = [
"Company Image": "",
"Company Description": companyDescriptionTextFieldText!,
"Start Date": dateToStart!,
"Decision Date": dateToDecide! ]
guard let imageData = imageSelected.jpegData(compressionQuality: 0.5) else {
return
}
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
storageCompanyRef.putData(imageData, metadata: metadata, completion:
{ (StorageMetadata, error) in
if (error != nil) {
return
}
storageCompanyRef.downloadURL { (url, error) in
if let metadateImage = url?.absoluteString {
dict["Company Image"] = metadateImage
companyRef.updateChildValues(dict, withCompletionBlock: {
(error, ref) in
if error == nil {
print("Done")
return
}
}
)
}
}
storageRef.updateMetadata(metadata) { metadata, error in
if error != nil {
//Uh-oh, an error occurred!
} else {
// Updated metadata for 'images/forest.jpg' is returned
}
}
})
considerationInfluencerRef.updateChildValues(values as [AnyHashable : Any]) { (error, ref) in
if error != nil {
print(error ?? "")
return
}
self.navigationController?.popViewController(animated: true)
}
}
func createDatePickerForStart() {
// center text in field
startDateTextFieldConsiderations.textAlignment = .center
// toolbar
let toolbar = UIToolbar()
toolbar.sizeToFit()
// barbutton
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(donePressedStart))
toolbar.setItems([doneButton], animated: true)
// assign toolbar to textfield
startDateTextFieldConsiderations.inputAccessoryView = toolbar
// assign datePicker to text field
startDateTextFieldConsiderations.inputView = datePickerS
// date picker mode
datePickerS.datePickerMode = .date
}
func createDatePickerForEnd() {
// center text in field
endDateTextFieldConsiderations.textAlignment = .center
// toolbar
let toolbar = UIToolbar()
toolbar.sizeToFit()
// barbutton
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(donePressedEnd))
toolbar.setItems([doneButton], animated: true)
// assign toolbar to textfield
endDateTextFieldConsiderations.inputAccessoryView = toolbar
// assign datePicker to text field
endDateTextFieldConsiderations.inputView = datePickerE
// date picker mode
datePickerE.datePickerMode = .dateAndTime
}
@objc func donePressedStart() {
// formatter
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
startDateTextFieldConsiderations.text = formatter.string(from: datePickerS.date)
self.view.endEditing(true)
}
@objc func donePressedEnd() {
// formatter
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .medium
endDateTextFieldConsiderations.text = formatter.string(from: datePickerE.date)
self.view.endEditing(true)
}
}
extension ConsiderationsTestViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//print("did Finish Picking Media")
if let image = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerEditedImage")] as? UIImage{
selectedImage = image
CompanyImage.image = image
}
dismiss(animated: true, completion: nil)
}
}
extension ConsiderationsTestViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ConsiderationsTestViewController.numberOfPeople.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: AddPersonCell, for: indexPath) as! ConsiderationsCell
return cell
}
}
Here is the code for the view controller where I select the user and input their respective information:
import UIKit
import Firebase
class DropDownCellViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UITextFieldDelegate {
var numberOfPeople = [String]()
var users = [User]()
var userName = [String]()
var filteredNames: [String]!
let dropDownCell = "dropDownCell"
var emptyField = [String]()
@IBOutlet weak var nameTextField: NoCopyPasteUITextField!
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var gridTextField: UITextField!
@IBOutlet weak var storyTextField: UITextField!
@IBOutlet weak var compensationTextField: UITextField!
@IBAction func textFieldChanged(_ sender: AnyObject) {
tableView.isHidden = true
}
@IBAction func cancelButtonTapped(_ sender: Any) {
self.navigationController?.popViewController(animated: true)
}
@IBAction func addButtonTapped(_ sender: Any) {
ConsiderationsTestViewController.numberOfPeople.append("\(nameTextField.text!)")
self.navigationController?.popViewController(animated: true)
print(ConsiderationsTestViewController.numberOfPeople)
}
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
updateDataArray()
tableView.register(UserCell.self, forCellReuseIdentifier: dropDownCell)
filteredNames = userName
tableView.delegate = self
tableView.dataSource = self
nameTextField.delegate = self
tableView.isHidden = true
// Manage tableView visibility via TouchDown in textField
nameTextField.addTarget(self, action: #selector(textFieldActive), for: UIControl.Event.touchDown)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
guard let touch:UITouch = touches.first else
{
return;
}
if touch.view != tableView
{
nameTextField.endEditing(true)
tableView.isHidden = true
}
}
@objc func textFieldActive() {
tableView.isHidden = !tableView.isHidden
}
// MARK: UITextFieldDelegate
func textFieldDidEndEditing(_ textField: UITextField) {
// TODO: Your app can do something when textField finishes editing
print("The textField ended editing. Do something based on app requirements.")
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return filteredNames.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: dropDownCell, for: indexPath) as!
UserCell
let user = users[indexPath.row]
cell.textLabel?.text = user.name
if let profileImageUrl = user.profileImageUrl {
cell.profileImageView.loadImageUsingCacheWithUrlString(urlString: profileImageUrl)
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 72
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Row selected, so set textField to relevant value, hide tableView
// endEditing can trigger some other action according to requirements
nameTextField.text = userName[indexPath.row]
tableView.isHidden = true
nameTextField.endEditing(true)
}
//Mark: Search Bar Config
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredNames = []
if searchText == "" {
filteredNames = userName
}
else {
for names in userName {
if names.lowercased().contains(searchText.lowercased()) {
filteredNames.append(names)
}
}
}
self.tableView.reloadData()
}
func updateDataArray() {
Database.database().reference().child("users").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.name = dictionary["name"] as? String
user.email = dictionary["email"] as? String
user.facebookUrl = dictionary["facebookUrl"] as? String
user.instagramUrl = dictionary["instagramUrl"] as? String
user.linkedInUrl = dictionary["linkedInUrl"] as? String
user.profileImageUrl = dictionary["profileImageUrl"] as? String
user.twitterUrl = dictionary["twitterUrl"] as? String
user.id = dictionary["id"] as? String
user.userType = dictionary["userType"] as? String
self.users.append(user)
self.userName.append(user.name!)
self.filteredNames.append(user.name!)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
}
I had a button in the original view controller that would print the array. I tested it before attempting to append the array. It was empty. I then added to people and tested it. It printed both the names but the table didn't change. I tried to dispatch.resync in the add button but it's too ambiguous. I really could use the help. Thanks! And thank you for the patience. I am new to coding and have no education in coding besides being self taught.
I found out how to reload the data. I just need to figure out how to set the labels equal to the textfield text. That way I can see it and be able to send it to firebase. The way I fixed it was by having my add button have the following code:
@IBAction func addButtonTapped(_ sender: Any) {
ConsiderationsTestViewController.numberOfPeople.append("\(nameTextField.text!)")
self.navigationController?.popViewController(animated: true)
print(ConsiderationsTestViewController.numberOfPeople)
DispatchQueue.main.async {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)
}
}
I then inserted this in the viewDidLoad of the view controller I wanted to reload:
NotificationCenter.default.addObserver(self, selector: #selector(loadList), name: NSNotification.Name(rawValue: "load"), object: nil)