Pass data through navigation back button

后端 未结 4 1232
一向
一向 2020-12-24 03:10

I am in this situation:

I am passing 4 array from Progress Table to Detail Exercise using prepare for segue and it works fine! The problem begin when I try

相关标签:
4条回答
  • 2020-12-24 03:50

    Simpler solution you can use self.navigationController?.viewControllers to access previous view controller as following:

    let vcsCount = self.navigationController?.viewControllers.count
    self.navigationController?.viewControllers[vcsCount! - 2].updateData
    

    updateData is the data member to update at previous view controller

    0 讨论(0)
  • 2020-12-24 03:56

    Typically, protocols and delegates are used to pass data back and forth between screens.

    // Define a delegate that is known to both view controllers
    protocol DetailsExerciseDelegate {
        func detailsWillDisappear(...);
    }
    
    class DetailsExerciseViewController {
        // Accept the delegate as a property on the details view controller
        var delegate : DetailsExerciseDelegate
    
        override func viewWillDisappear(animated : Bool) {
            super.viewWillDisappear(animated)
    
            // When you want to send data back to the caller
            // call the method on the delegate
            if let delegate = self.delegate {
                delegate.detailsWillDisappear(/* your data in one or more parameters */)
            }
        }
    }
    
    // Implement the delegate by adding the required function
    class ProgressTableViewController: DetailsExerciseDelegate {
        ...
    
        func detailsWillDisappear(...) {
            // When the child calls the function, update the screen
            historyView.isFirstTime = false
            historyView.arrayData = arrayDataDetails
            historyView.arrayRipetizioni = arrayRipetizioniDetails
            historyView.arrayPeso = arrayPesoDetails
            historyView.arrayRecupero = arrayRecuperoDetails
            historyView.tableView.reloadData()
        }
    
        override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
            if segue!.identifier == "DetailsExcercise" {
                // And finally, when launching the child view,
                // make sure to set the delegate.
                let viewController = segue!.destinationViewController as DetailsExerciseViewController
                viewController.delegate = self
            }
        }
    }
    

    That being said, it seems non-standard to try to save the data when clicking the back button. Are you sure you don't want to do this on "Done" instead?

    0 讨论(0)
  • 2020-12-24 04:00

    When you press the back button, the navigation controller will call navigationController(willShowViewController:) so you can use this to pass the data back to your initial view controller. An example is shown below:

    Using UINavigationControllerDelegate:

    class DetailsViewController: UIViewController, UINavigationControllerDelegate {
                                                            //     ^
        var data: [String] = []                             // Important!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            navigationController?.delegate = self
    
            data = ["data has changed!"]
        }
    }
    

    Swift 2:

    extension DetailsViewController: UINavigationControllerDelegate {
        func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
            if let controller = viewController as? ProgressTableViewController {
                controller.data = data    // Here you pass the data back to your original view controller
            }
        }
    }
    

    Swift 3:

    extension DetailsViewController: UINavigationControllerDelegate {
        func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
            (viewController as? ProgressTableViewController)?.data = data // Here you pass the to your original view controller
        }
    }
    

    In this example, the key is using the UINavigationControllerDelegate and setting the delegate of the navigation controller (in this case it's self). Having done this, you can send the data back to your initial view controller with the back button.

    Personally I prefer using a class for my data:

    Using a custom class for your data:

    class Data {
        var array: [String] = []
    }
    

    Progress view controller:

    class ProgressTableViewController: UITableViewController {
    
        var data = Data()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            data.array = ["some data"]
        }
    
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated)
    
            tableView.reloadData()
        }
    
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return data.array.count
        }
    
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = UITableViewCell()
    
            cell.textLabel?.text = data.array[indexPath.row]
    
            return cell
        }
    
        override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            performSegue(withIdentifier: "exerciseSegue", sender: self)
        }
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if segue.identifier == "exerciseSegue" {
                let destination = segue.destinationViewController as! DetailsViewController
                destination.data = data
            }
        }
    }
    

    Details view controller:

    class DetailsViewController: UIViewController {
    
        var data = Data()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            data.array = ["data has changed!"]
        }
    }
    

    In the last example, you don't have to worry about passing around data. Whenever you change the data, the controllers using the same class, will have the changes as well.

    0 讨论(0)
  • 2020-12-24 04:08

    Also, you can use this extension:

    extension UINavigationController {
        func viewController<T: UIViewController>(class: T.Type) -> T? {
    
            return viewControllers.filter({$0 is T}).first as? T
        }
    }
    
    //
    
    if let controller = navigationController?.viewController(class: MainViewController.self) {
         controller.data = data
    }
    
    navigationController?.popViewController(animated: true)
    
    0 讨论(0)
提交回复
热议问题