Reputation: 47
I have this tableviewcontroller and detailviewcontroller which has a text field, when the user clicks the tableviewcell it goes to text field and the user could able to edit the content!!
How should I update the table view with new content in the text field through back button?
let sectionTitles = ["ongoing","Done"]
var list = [String]()
class MasterViewController: UITableViewController {
var detailViewController: DetailViewController? = nil
var objects = sectionTitles.map({_ in return [Any]()})
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
navigationItem.leftBarButtonItem = editButtonItem
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:)))
navigationItem.rightBarButtonItem = addButton
if let split = splitViewController {
let controllers = split.viewControllers
detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
}
@objc
func insertNewObject(_ sender: Any) {
objects[0].insert("Task 1", at: 0)
let indexPath = IndexPath(row: 0, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
}
// MARK: - Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = objects[indexPath.section][indexPath.row] as! String
let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
}
class DetailViewController: UIViewController,UINavigationControllerDelegate {
@IBOutlet weak var detailDescription: UITextField!
func configureView() {
// Update the user interface for the detail item.
if let detail = detailItem {
if let label = detailDescription {
label.text = detail.description
list.append(label.text!)
}
}
}
}
Upvotes: 0
Views: 263
Reputation: 285260
I recommend to use a callback closure to update the model and reload the row. The callback is called in viewDidDisappear
. The code in the closure checks if the values are different and updates the model and reloads the row if necessary.
In DetailViewController create a callback
var callback : ((String)->())?
In viewDidDisappear
call the callback (or maybe already in viewWillDisappear
)
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
callback?(detailDescription.text!)
}
In MasterViewController add the closure in prepare(for
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = objects[indexPath.section][indexPath.row] as! String
let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.callback = { newValue in
if object != newValue {
self.objects[indexPath.section][indexPath.row] = newValue
self.tableView.reloadRows(at: [indexPath], with: .automatic)
}
}
controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
Upvotes: 1
Reputation: 457
You could use the delegate pattern:
protocol DetailViewDelegate: class {
func detailViewDidUpdate(from: String?, to: String?)
}
class DetailViewController : UIViewController {
var detailItem: String?
weak var delegate: DetailViewDelegate?
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.textField.text = detailItem
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.delegate?.detailViewDidUpdate(from: detailItem, to: textField.text)
}
}
Then in your MasterViewController:
extension MasterViewController: DetailViewDelegate {
func detailViewDidUpdate(from: String?, to: String?) {
guard let originalValue = from, let newValue = to else {
return
}
if let indexPath = self.objects.index(of: originalValue) {
self.objects[indexPath] = newValue
// We assume here that there is only one section
let newIndexPath = IndexPath(row: indexPath, section: 0)
self.tableView.reloadRows(at: [newIndexPath], with: .automatic)
}
}
}
Don't forget to assign the DetailViewController's delegate variable in your MasterController prepare(for segue: UIStoryboardSegue, sender: Any?) method
Upvotes: 0
Reputation: 1990
When you tapped back button, viewWillAppear will be called, its one View Controller Lifecycle
for example
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tableView.reloadData()
}
Upvotes: 0