web-dev-qa-db-fra.com

Passer des données via le bouton de navigation retour

Je suis dans cette situation:

 img1

Je passe 4 tableaux de la table de progression à l’exercice de détail en utilisant prepare for segue et cela fonctionne bien! Le problème commence lorsque j'essaie de transmettre les données du contrôleur d'exercice détaillé au contrôleur de table de progression. J'aimerais utiliser le bouton de navigation par défaut pour revenir à la vue parent. En fait, j'utilise ce code mais cela ne fonctionne pas, ainsi les données passent de la vue enfant à la vue parent mais je ne peux pas voir le résultat dans la table de progression. après le viewDidLoad et cela ne fonctionne pas. Toute suggestion? Je vous remercie.

override func viewWillDisappear(animated : Bool) {
    super.viewWillDisappear(animated)

    if (self.isMovingFromParentViewController()){
        print("n'drio")

        let historyView = self.storyboard!.instantiateViewControllerWithIdentifier("historyView") as! HistoryTableViewController
        historyView.isFirstTime = false
        historyView.arrayData = arrayDataDetails
        historyView.arrayRipetizioni = arrayRipetizioniDetails
        historyView.arrayPeso = arrayPesoDetails
        historyView.arrayRecupero = arrayRecuperoDetails
        historyView.tableView.reloadData()
    }
}
13
Luca Alberto

Lorsque vous appuyez sur le bouton Précédent, le contrôleur de navigation appelle navigationController(willShowViewController:) afin que vous puissiez l'utiliser pour transmettre les données à votre contrôleur de vue initial. Un exemple est présenté ci-dessous:

Utilisation de 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
    }
}

Dans cet exemple, la clé utilise UINavigationControllerDelegate et définit le délégué du contrôleur de navigation (dans ce cas, c'est self). Ceci fait, vous pouvez renvoyer les données à votre contrôleur de vue initial avec le bouton Précédent.

Personnellement, je préfère utiliser une classe pour mes données:

Utilisation d'une classe personnalisée pour vos données:

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

Contrôleur de vue de progression:

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
        }
    }
}

Contrôleur de vue de détails:

class DetailsViewController: UIViewController {

    var data = Data()

    override func viewDidLoad() {
        super.viewDidLoad()

        data.array = ["data has changed!"]
    }
}

Dans le dernier exemple, vous n'avez pas à vous soucier de la transmission de données. Chaque fois que vous modifiez les données, les contrôleurs utilisant la même classe auront également les modifications.

39
Eendje

En règle générale, les protocoles et les délégués sont utilisés pour échanger des données entre les écrans.

// 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
        }
    }
}

Cela étant dit, il semble inhabituel d'essayer de sauvegarder les données en cliquant sur le bouton Précédent. Êtes-vous sûr de ne pas vouloir faire cela sur "Terminé"?

4
Bryan

Solution plus simple, vous pouvez utiliser self.navigationController? .ViewControllers pour accéder au contrôleur de vue précédent comme suit:

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

updateData est le membre de données à mettre à jour sur le contrôleur de vue précédent

2
ossamacpp

En outre, vous pouvez utiliser cette 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
ChikabuZ