2016-02-10 24 views
20

Utworzono dwa kontrolery widoku. Stworzyłem przejście od pierwszego do drugiego, aby przekazać dane. Teraz chcę przekazać dane z drugiego kontrolera widoku do pierwszego. Przeszedłem przez wiele podobnych pytań i nie jestem w stanie ich wdrożyć, ponieważ brakuje mi wiedzy na temat rozwijania prac.Przekazywanie danych przy rozwijaniu segue

ViewController.swift

class ViewController: UIViewController 
{ 
    var dataRecieved: String? 
    @IBOutlet weak var labelOne: UILabel! 
    @IBAction func buttonOne(sender: UIButton) 
    { 
     performSegueWithIdentifier("viewNext", sender: self) 
    } 
    override func prepareForSegue(segue: (UIStoryboardSegue!), sender: AnyObject!) 
    { 

     var svc: viewControllerB = segue.destinationViewController as! viewControllerB 
     svc.dataPassed = labelOne.text 
    } 
} 

Przepuszcza dane do dataPassed w widoku kontrolera "viewControllerB". Powiedzmy, teraz chcę przekazać niektóre dane z viewControllerB do dataRecieved w ViewController. W jaki sposób mogę to zrobić tylko przy użyciu opcji odpinania, a nie przy użyciu delegata. Jestem całkiem nowy na szybkie, doceniłbym szczegółowe wyjaśnienie.

+0

Po prostu zaimplementuj 'prepareForSegue' w rozwijanym kontrolerze widoku i uzyskaj dostęp do' destinationViewController', który będzie kontrolerem widoku, do którego się rozwijasz. Najprawdopodobniej będziesz chciał podać relację rozwijania i identyfikator w swoim scenorysie – Paulw11

+0

Daje błąd "nie ma segue z identyfikatorem" btnSubmitSegue "" ". Dodałem identyfikator segue w kontrolerze widoku. Używam tylko jednej ścieżki do połączenia obu kontrolerów widoku. Wydaje mi się, że rozwijanie segue po prostu powraca do poprzedniego kontrolera widoku bez żadnych dodatkowych fragmentów? Czy możesz wyjaśnić szczegółowo?Jakiś kod byłby doceniony :) – ebby94

+0

Tworzysz relind unwind jak zwykle - przeciągnij do ikony 'exit' w scenie. Teraz w inspektorze obiektów po lewej stronie zobaczysz rozwijaną relę wymienioną poniżej kontrolera widoku, ikony pierwszej odpowiedzi i wyjścia. Możesz kliknąć na rozwijaną zmianę i nadać jej identyfikator w inspektorze po prawej stronie. – Paulw11

Odpowiedz

43

Øyvind Hauge pokazał mi do tego samego rozwiązania metody, ale jak już się rozpoczął z bardziej szczegółową odpowiedź, będę go dodać również.


Powiedzmy twoje dwie widok kontrolerów nazywane są następująco:

  • punkt Master/entry: ViewController(vcA)
  • widok wtórne: ViewControllerB(vcB)

można skonfigurować segue z (vcA) -> (vcB) jak to zrobiliście w przykładzie

/* in ViewController.swift */ 

// ... 

// segue ViewController -> ViewControllerB 
override func prepareForSegue(segue: (UIStoryboardSegue!), sender: AnyObject!) 
{ 
    if segue.identifier == "viewNext" { 
     let viewControllerB = segue.destinationViewController as! ViewControllerB 
     viewControllerB.dataPassed = labelOne.text 
    } 
} 

Nieco trudne, następny krok polega na tym, przy użyciu tego sposobu, segue stosowany do przekazywania danych z powrotem z(vcB)do(vcA) jest również dodana do źródła (vcA) jako metody @IBAction (a niż, jak można się było spodziewać, dodać do źródła (vcB)).

/* in ViewController.swift */ 

// ... 

// segue ViewControllerB -> ViewController 
@IBAction func unwindToThisView(sender: UIStoryboardSegue) { 
    if let sourceViewController = sender.sourceViewController as? ViewControllerB { 
     dataRecieved = sourceViewController.dataPassed 
    } 
} 

można następnie połączyć powiedzmy, przycisk w (vcB) do tej rozwijania działań w (vcA) poprzez ręczną Exit segue w (vcB):

enter image description here

Poniżej następuje kompletny przykład przechodząc tekst z (vcA) do (vcB); (prawdopodobnie) modyfikując ten tekst za pomocą UITextField, ostatecznie zwracając (ewentualnie) zmodyfikowany tekst do (vcA).


(vcA) źródło:

/* ViewController.swift: Initial view controller */ 
import UIKit 

class ViewController: UIViewController { 

    var dataRecieved: String? { 
     willSet { 
      labelOne.text = newValue 
     } 
    } 
    @IBOutlet weak var labelOne: UILabel! 

    @IBAction func buttonOne(sender: UIButton) { 
     performSegueWithIdentifier("viewNext", sender: self) 
    } 

    // set default labelOne text 
    override func viewDidLoad() { 
     super.viewDidLoad() 

     labelOne.text = "Default passed data" 
    } 

    // segue ViewController -> ViewControllerB 
    override func prepareForSegue(segue: (UIStoryboardSegue!), sender: AnyObject!) 
    { 
     if segue.identifier == "viewNext" { 
      let viewControllerB = segue.destinationViewController as! ViewControllerB 
      viewControllerB.dataPassed = labelOne.text 
     } 
    } 

    // segue ViewControllerB -> ViewController 
    @IBAction func unwindToThisView(sender: UIStoryboardSegue) { 
     if let sourceViewController = sender.sourceViewController as? ViewControllerB { 
      dataRecieved = sourceViewController.dataPassed 
     } 
    } 
} 

(vcB) źródło (zauważ, że UITextFieldDelegate delegat tutaj służy tylko do „lokalnie” mutowania wartość właściwości dataPassed, która zostanie zwrócona do (vcA) i przypisany do dataRecieved własność tego ostatniego)

/* ViewControllerB.swift */ 
import UIKit 

class ViewControllerB: UIViewController, UITextFieldDelegate { 

    var dataPassed : String? 
    @IBOutlet weak var textField: UITextField! 

    // set default textField text to the data passed from previous view. 
    override func viewDidLoad() { 
     super.viewDidLoad() 

     textField.text = dataPassed 

     // Handle the user input in the text field through delegate callbacks 
     textField.delegate = self 
    } 


    // UITextFieldDelegate 
    func textFieldShouldReturn(textField: UITextField) -> Bool { 
     // User finished typing (hit return): hide the keyboard. 
     textField.resignFirstResponder() 
     return true 
    } 

    func textFieldDidEndEditing(textField: UITextField) { 
     dataPassed = textField.text 
    } 
} 

Przykładowe wykonanie:

enter image description here

+0

Dziękuję bardzo za szczegółowe wyjaśnienie! Pomogło mi to lepiej zrozumieć :) – ebby94

+0

Może to przede mną, ale co to jest "newValue" w "willSet { labelOne.text = newValue }" –

+0

@DarkhorseFantasySports nie martw się: jest to domyślna nazwa dla nowej wartości, która ma być set: _ "Jeśli zaimplementujesz obserwatora' willSet', to przekazuje on nową wartość właściwości jako stały parametr.Możesz określić nazwę dla tego parametru jako część implementacji 'willSet' .Jeśli nie napiszesz nazwy parametru oraz nawiasy w ramach twojej implementacji, parametr jest udostępniany z domyślną nazwą parametru "newValue". "_ - Od [Przewodnik językowy Swift - Właściwości] (https://developer.apple.com/library/content/documentation/ Swift/Conceptual/Swift_Programming_Language/Properties.html). – dfri

7

To w jaki sposób to zrobić:

  1. Załóż wylot w widoku kontrolera 1 w następujący sposób:

    @IBAction func unwindToViewController1(segue: UIStoryboardSegue) { 
    
        let foo = segue.sourceViewController.foo 
    
        // TODO: Use foo in view controller 1 
    } 
    
  2. Połącz widok kontroler 2 (VC jesteś odwijania z) jak pokazano poniżej. Przeciągnij z żółtego okręgu w vc2 na "Exit". Powinien pojawić się kontroler IBAction from view controller 1. Wybierz to. enter image description here

  3. Teraz, kiedy tylko odpoczynek z widokiem na kontrolerze 2, metoda w widoku kontrolera 1 unwindToViewController1: zostanie sprawdzony.

  4. Tutaj można pobrać żądaną właściwość z kontrolera widoku 2. Zwróć uwagę, że musisz odrzucić segue.sourceViewController do niestandardowej podklasy kontrolera widoku, aby uzyskać odpowiednią właściwość.

+0

Dzięki! To odpowiadało na moje pytanie :) – ebby94

+0

Cieszę się, że się udało –

0

Jeśli aplikacja obsługuje iOS 9+ można przekazać dane prawie taki sam jak prepareForSegue użyć UIStoryboardUnwindSegueSource który ma sender właściwość, która jest dokładnie taka sama jak nieruchomości w prepare(for segue: UIStoryboardSegue, sender: Any?)sender.

Jak go używać:

  1. Utwórz metodę unwindTo.

Uwaga: Łączenie metody unwindTo jest taka sama jak @ Øyvind Hauge i @dfri wyjaśnione w swoich odpowiedziach.

  1. Wewnątrz kontrolera widok, który chcesz odprężyć się, zastąpić metodę canPerformUnwindSegueAction(_:from:withSender:)
  2. Wewnątrz tej metody, należy sprawdzić, czy typ fromViewController jest typem pan przyjdzie z
  3. If jest to odlew właściwość sender do rodzaju wysłanego i powrócić prawda
  4. Else, return false

Code Snip (Swift 4.0):

@IBAction func unwindToMyFirstViewController(segue: UIStoryboardSegue) {} 

override func canPerformUnwindSegueAction(_ action: Selector, from fromViewController: UIViewController, withSender sender: Any) -> Bool { 
    if fromViewController is MyCustomViewController, 
     let customType = sender as? MyCustomType { 
     return true 
    } 
    return false 
}