I have a ViewController that has a UIBarButtonItem on it, I need the data from the TextField (textField is in the ViewController) to be passed to the TableViewController when the button is clicked without switching to it (TableViewController). ViewController and TableController are associated with TabBarController. ViewController have NavigationController. My version of the code does not work. By clicking on the button, the data is not saved. And in the TableViewController there is only one empty cell.
The CallViewController
has two text fields (because you haven't indicated how you are loading a "Contact image"), a "message label", and the "Save" button up in the nav bar.
We start with the Contact struct - I'll use two strings:
struct Contact {
var title: String
var imageName: String
}
Now we'll create a Singleton data manager class:
class MyContactData {
var myContacts: [Contact] = []
static let shared: MyContactData = {
let instance = MyContactData()
// setup code
return instance
}()
}
In the Call view controller, when we tap the Save button:
class CallViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var nameTextField: UITextField!
@IBOutlet var imageTextField: UITextField!
@IBOutlet var msgLabel: UILabel!
func textFieldDidBeginEditing(_ textField: UITextField) {
msgLabel.text = ""
}
@IBAction func saveContact(_ sender: UIBarButtonItem) {
print("save")
view.endEditing(true)
let title = nameTextField.text ?? "Unknown"
let imgName = imageTextField.text ?? "Unknown"
// create a Contact
let c = Contact(title: title, imageName: imgName)
// append it to shared data in the data manager singleton
MyContactData.shared.myContacts.append(c)
// show that we "saved" the data
msgLabel.text = "Saved:\n\(title)\n\(imgName)"
// clear the text fields
nameTextField.text = ""
imageTextField.text = ""
}
}
and, finally, our History table view controller will look like this:
class HistroyCallsTableViewController: UITableViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableView.reloadData()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// our data is in our shared data manager class
return MyContactData.shared.myContacts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? ContactTableViewCell {
// our data is in our shared data manager class
let title = MyContactData.shared.myContacts[indexPath.row].title
let imgName = MyContactData.shared.myContacts[indexPath.row].imageName
cell.titleContactLabel.text = title
// try to load the image as named asset
if let img = UIImage(named: imgName) {
cell.contactPhotoimaveView.image = img
} else {
// try to load it as a system image
if let img = UIImage(systemName: imgName) {
cell.contactPhotoimaveView.image = img
} else {
// no image available, so let's use the row number
// as an SF Symbol "indice"
if let img = UIImage(systemName: "\(indexPath.row).circle") {
cell.contactPhotoimaveView.image = img
}
}
}
return cell
}
return UITableViewCell()
}
}
class ContactTableViewCell: UITableViewCell {
@IBOutlet var titleContactLabel: UILabel!
@IBOutlet var contactPhotoimaveView: UIImageView!
}
When we run the app, we'll enter "Bob" and "car":
Tap "Save" and we see this:
Enter "Joe" and "sailboat" ... tap Save:
Tap the Tab icon for History:
Now, most likely, you will want to save -- persist -- the data between app uses? In that case, instead of using the simple MyContactData
singleton class as shown, you would use something like Core Data
... but the process would be the same:
- allow user to enter data
- on Save tap, save the data via Core Data
- on navigating to the table view controller, populate it from Core Data