2016-01-22 6 views
13

ich in dieser Situation bin:Pass-Daten durch Navigation Zurück-Taste

img1

Ich bin vorbei 4-Array von Fortschritt Tabelle to Detail Übung für segue mit vorbereiten und es funktioniert gut! Das Problem beginnt, wenn ich versuche, die Daten vom Detail-Exercise-Controller an den Progress-Tabellen-Controller zurückzugeben. Ich möchte die Standard-Navigationstaste verwenden, um zur übergeordneten Ansicht zurückzukehren. Eigentlich verwende ich diesen Code, aber es funktioniert nicht, gut die Daten gehen von der Kind- zu der Elternansicht, aber ich kann das Ergebnis in der Fortschrittstabelle nicht sehen, scheint wie ich muss aktualisieren, aber ich habe auch versucht, die reloadData nach der ViewDidLoad und es funktioniert nicht. Irgendein Vorschlag? Vielen Dank.

+0

Statt zurückzugeben Sie können auch eine benutzerdefinierte Klasse mit den Arrays als Klasseneigenschaften erstellen. Wenn Sie diese also im Trainingsansicht-Controller ändern, werden sie auch im Fortschrittsansicht-Controller geändert. – Eendje

Antwort

29

Wenn Sie die Zurück-Taste drücken, ruft der Navigationscontroller navigationController(willShowViewController:) auf, damit Sie die Daten zurück zum ursprünglichen Ansichtscontroller übertragen können.

Verwenden von 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: Ein Beispiel wird unten gezeigt

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 diesem Beispiel verwendet der Schlüssel UINavigationControllerDelegate und legt den Delegierten des Navigationscontrollers fest (in diesem Fall ist es self). Nachdem Sie dies getan haben, können Sie die Daten mit der Schaltfläche Zurück an Ihren ursprünglichen View-Controller zurücksenden.

Persönlich bevorzuge ich eine Klasse für meine Daten mit:

eine benutzerdefinierte Klasse für Ihre Daten verwenden:

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

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

Einzelheiten View-Controller:

class DetailsViewController: UIViewController { 

    var data = Data() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

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

Im letzten Beispiel müssen Sie sich keine Gedanken über die Weitergabe von Daten machen. Wenn Sie die Daten ändern, haben die Controller, die dieselbe Klasse verwenden, ebenfalls die Änderungen.

+0

Ich schätze, Sie antworten, ich wählte die Klasse 'Bridge' Weg und es funktioniert sehr gut! Vielen Dank! –

+0

Heute eine neue Sache gelernt. Vielen Dank Eendje :) –

+0

Warum die down vote? Möchte es wissen, damit ich es korrigieren kann. – Eendje

4

In der Regel werden Protokolle und Delegaten verwendet, um Daten zwischen Bildschirmen hin- und herzuübertragen.

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

Das gesagt, es scheint nicht Standard zu versuchen, die Daten zu speichern, wenn Sie auf die Zurück-Schaltfläche klicken. Sind Sie sicher, dass Sie dies nicht auf "Done" tun möchten?

+0

Vielen Dank für die Beantwortung meiner Frage, aber Ihr Code ist überhaupt nicht verständlich! in den 'func detailsWillDisappear' wie kann ich Daten zurück zur Elternansicht ?? wo hast du historyView initialisiert ?? –

+2

Beachten Sie, dass Ihre Klasse 'DetailsExerciseViewController' einen starken Referenzzyklus hat, da der Delegat verhindert, dass die Zuordnung aufgehoben wird. Wenn man es "schwach" macht, wird dieses Problem gelöst. – Eendje

+0

Wie @Eendje in seinem Kommentar sagte, müssen Sie den Delegierten mit schwachen Referenzen implementieren, um jeden Retain-Zyklus zu vermeiden –

2

Einfachere Lösung können Sie Self.navigationController verwenden ?.Viewcontrollers als vorherige View-Controller für den Zugriff auf folgenden:

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

update das Datenelement ist bei vorherigem View-Controller

0

Auch zu aktualisieren, können Sie diese Erweiterung verwenden:

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)