Dismiss my view controller but "prepare" the view controller underneath - ios

I have a modally-presented ViewController that has a UITableView inside it. When the user clicks "Days", it shows this view controller (modally). Here's my Storyboard:
What I want to do is, when I click one of the cells in the table view in the modal, I want to dismiss the modal, but also load new data in the root view controller.
How can I have access to the root view controller from a segued view controller?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.dismiss(animated: true, completion: nil)
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as! DayView
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.day = days![indexPath.row]
}
}
I want something like what I've written above, but while my modal does get dismissed, but what I want is for somehow the code in the prepare function to fire when a TableViewCell is clicked.

A shorter and simpler method than protocol/delegate is to create a closure:
For sending a String back, In First ViewController:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let viewControllerB = segue.destination as? ViewControllerB {
viewControllerB.callback = { message in
//Do what you want in here!
}
}
}
In ViewControllerB:
var callback : ((String) -> Void)?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
callback?("Your Data")
self.dismiss(animated: true, completion: nil)
}

you are in the right path,you need to add two more functions 1. unwindsegue and one this is not destination its source so you need change to source from destination.
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.source as! DayView
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.day = days![indexPath.row]
}
}
for Reference : How to Pass Data in an Unwind Segue

Related

performSegue view not in window hierarchy

I'm trying to perform a segue to another view controller with this code:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
placemarkIndex = indexPath.row
self.view.endEditing(true)
self.dismiss(animated: true, completion: nil)
self.performSegue(withIdentifier: K.Segues.cityViewController, sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == K.Segues.cityViewController {
let destinationVC = segue.destination as! CityViewController
if let index = placemarkIndex, let city = cities?[index] {
destinationVC.location = city
}
}
}
the segue works when I search the table view and select the row while searching, however, it returns the following error when clicking on a row without searching action enabled:
Warning: Attempt to present <Simple_Forecast.CityViewController: 0x7fadc9893a00> on <Simple_Forecast.SearchViewController: 0x7fadcc12f390> whose view is not in the window hierarchy!
How can I solve this?
Thank you

Prepare for segue in TableViewDelegate methods

[SOLVED]
Let me explain my problem;
I have a bunch of Event object which appears in tableView cells.
And these objects store in events array
var events: [Event]
Also i have another view controller(DetailViewContoller), in that view controller i have a variable for receiving event object from tableview.
import UIKit
class EventDetailViewController: UIViewController {
var event: Event?
override func viewDidLoad() {
super.viewDidLoad()
print(event?.name)
}
When i tapped the cells i want to pass my current event object to variable(indicated on above) in DetailViewController. So i tried this ->
extension EventListViewcontroller:UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Whenever cells tapped, related object needs to pass DetailViewController
performSegue(withIdentifier: K.Segues.eventListToDetail, sender: self)
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == K.Segues.eventListToDetail {
let VC = segue.destination as! EventDetailViewController
VC.event = events[indexPath.row]
}
}
}
But unfortunately after segue performed when i checked the event variable in DetailViewController it was shown as a nil. So question is, how can i pass my tapped event cell to other view controller?
Note: i've found this topic How do you test UIStoryBoard segue is triggered by didSelectRow(at:) but it didn't help my problem...
In your class
class ViewController: EventListViewcontroller {
var selectedIndex: IndexPath? = nil
}
And change your code in didSelect as
extension ViewController:UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Whenever cells tapped, related object needs to pass DetailViewController
self.selectedIndex = indexPath
performSegue(withIdentifier: K.Segues.eventListToDetail, sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let indexPath = self. selectedIndex, segue.identifier == K.Segues.eventListToDetail {
let VC = segue.destination as! EventDetailViewController
VC.event = events[indexPath.row]
}
}
}
Hope this helps

Receiver has no segue with identifier 'goToDetail'

I've double-checked that my identifier is spelled correctly in the storyboard and that the segue is pointed in the right direction, but I keep receiving this error. Could someone take a look at my code to see if I'm missing something?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedData = tableData[indexPath.row]
tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "goToDetail", sender: selectedData)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DetailViewController {
destination.vocab.text = sender as? String
}
}
Edit:
segue can be used only with if you have a UINavigationController that will handle the navigation. You performing a segue to UINavigationController. UINavigationController should be at the root of your storyboard.
In your didSelectRowAt function change
performSegue(withIdentifier: "goToDetail", sender: selectedData)
To NavigationController Identifier (Note if you do not have identifier already set up in storyboard you will need to do that first)
performSegue(withIdentifier: "goToNavigationConrtoller", sender: selectedData)
And then change the prepareForSegue function to below.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//check destination for segue is Navigation controller
if let navVC = segue.destinationViewController as? UINavigationController {
// get hold of the first viewController.
if let destination = navVC.viewControllers[0] as? DetailViewController {
destination.vocab.text = sender as? String
//all the other code you need
}
}
}

How I can transfer data between controllers when returning to the last screen? Swift

In the application, I am asked to select a category, when I click, I move to the next screen from the tableView, and when I click on the desired category, it should be saved and return to the previous controller, where instead of "select a category" my chosen category will be.
I using by this method navigationController?.popViewController(animated: true), which brings me back to the last screen.
As I understand it, prepare is not called, but since I know exactly where I'm going, I can, in the method from which I call pop ..., get access to the controller I am switching to and pass it the necessary properties? But how?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let currentCell = categories[indexPath.row]
/?
/?
navigationController?.popViewController(animated: true)
}
When you go to the select screen do
let vc = ///
vc.delegate = self
// push
then inside didASelectRowAt
class CategoryViewController:UIViewController {
weak var delegate:PreviousVC?
////
}
delegate?.sendData(someData)
navigationController?.popViewController(animated: true)
Another option inside didASelectRowAt to
// access previous vc
let previousVC = self.navigationController!.viewControllers[self.navigationController!.viewControllers.count - 2] as! PreviousVc
previousVC.sendData(someData)
// pop here
Edit: inside the firstVC
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondVC = segue.destination as? SecondViewController {
secondVC.delegate = self
}
}
You can pass the selected category to the previous view controller using closure
class FirstViewController: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondVC = segue.destination as? SecondViewController {
secondVC.selectedOption = { selectedOption in
print(selectedOption)
//change category title here
}
}
}
}
class SecondViewController: UIViewController {
var selectedOption: ((String) -> Void)?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedOption?("Selected Option String")
navigationController?.popViewController(animated: true)
}
}
Maybe you should pass "Completion handler" when you move to your category selection controller like
(String)->(Void)
and when you pop it, pass your category in this clouser

Swift - pass data from tableview to third viewcontroller

I have too much code to paste it all in, so I'm going to be vague. I think I just need a general idea of what to do, and then I'll be able to do it.
I have a beautiful table built with a list of local businesses. When you click on one, it opens up the DetailView, with some great information about the business. I have a MAP button on the DetailView that triggers Thirdview with a Mapview inside of it.
I'm having issues retrieving data from the cells in the TableView in the Thirdview.
My views:
Tableview => DetailView => Thirdview
In my Thirdview, can I call the information from Tableview?
Or is it easier to pass the information from DetailView to Thirdview?
Thanks!
TableView
var objects: [MyObject] = []
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let myObject = objects[indexPath.row]
}
override func prepare(for segue: UIStoryboardSegue, sender: Any) {
if segue.identifier == "mySegue" {
let detailVC = segue.destination as! MyDetailVC
detailVC.dataFromTableView = myObject
}
}
Detail View
var dataFromTableView = MyObject()
override func prepare(for segue: UIStoryboardSegue, sender: Any) {
if segue.identifier == "mySegue" {
let thirdVC = segue.destination as! MyThirdViewController
thirdVC.dataFromDetailView = dataFromTableView
}
}
Third View
var dataFromDetailView = MyObject()
override func viewDidLoad() {
print(dataFromDetailView)
}

Resources