Reputation: 155
I'm trying to dismiss a modal view and return back to the view controller that was "sent" from, while keeping the data that was entered in the modal view. If I understand correctly I need to use delegates/protocols for this but I'm having a lot of trouble understanding how to actually implement it in this situation.
Basically a user can call a modal view to enter some information in text fields, and when they hit save this function is called:
func handleSave() {
guard let newProductUrl = NSURL(string: urlTextField.text!) else {
print("error getting text from product url field")
return
}
guard let newProductName = self.nameTextField.text else {
print("error getting text from product name field")
return
}
guard let newProductImage = self.logoTextField.text else {
print("error getting text from product logo field")
return
}
// Call save function in view controller to save new product to core data
self.productController?.save(name: newProductName, url: newProductUrl as URL, image: newProductImage)
// Present reloaded view controller with new product added
let cc = UINavigationController()
let pController = ProductController()
productController = pController
cc.viewControllers = [pController]
present(cc, animated: true, completion: nil)
}
Which calls the self.productController?.save
function to save the newly entered values into core data, and reloads the productController
table view with the new product.
However the issue I'm running into, is that the productController
table view is dynamically set depending on some other factors, so I just want to dismiss the modal view once the user has entered the data, and return back to the page the modal view was called from.
EDIT: attempt at understanding how to implement the delegate -
ProductController is the parent class that the user gets to the modal view from:
protocol ProductControllerDelegate: class {
func getData(sender: ProductController)
}
class ProductController: UITableViewController, NSFetchedResultsControllerDelegate, WKNavigationDelegate {
override func viewDidLoad() {
super.viewDidLoad()
weak var delegate:ProductControllerDelegate?
}
func getData(sender: ProductController) {
}
And AddProductController is the modally presented controller where the user enters in the data then handleSave
is called and I want to dismiss and return to the ProductController tableview it was called from:
class AddProductController: UIViewController, ProductControllerDelegate {
override func viewDidDisappear(_ animated: Bool) {
// error on this line
getData(sender: productController)
}
Upvotes: 0
Views: 704
Reputation: 16347
If the sole purpose of your protocol is to return the final state of the view controller its usually easier and clearer to use an unwind segue instead of a protocol.
Steps:
1) In the parent VC you make a @IBAction unwind(segue: UIStoryboardSegue) method
2) In the storyboard of the presented ViewController you control drag from either the control you want to trigger the exit or from the yellow view controller itself(if performing the segue in code) on to the orange exit icon.
your code should look like:
@IBAction func unwind(segue: UIStoryboardSegue) {
if let source = segue.source as? MyModalViewController {
mydata = source.data
source.dismiss(animated: true, completion: nil)
}
}
Edit here is the hacky way to trigger and unwind from code without storyboard; I do not endorse doing this:
guard let navigationController = navigationController,
let presenter = navigationController.viewControllers[navigationController.viewControllers.count - 2] as? MyParentViewController else {
return
}
presenter.unwind(UIStoryboardSegue(identifier: String(describing: self), source: self, destination: presenter))
Upvotes: 1
Reputation: 3711
Basically you need to create a delegate into this modal view. Let's say you have ParentViewController which creates this Modal View Controller. ParentViewController must implement the delegate method, let´s say retrieveData(someData).
On the Modal View Controller, you can use the method viewWillDisappear() to trigger the delegate method which the data you want to pass to the parent:
delegate.retrieveData(someData)
If you have issues understanding how to implement a delegate you can check this link
Upvotes: 0