web-dev-qa-db-fra.com

Transmission de données avec déroulement de séquence

J'ai créé deux contrôleurs de vue. J'ai créé une séquence du premier au second pour transmettre les données. Maintenant, je veux transmettre des données du deuxième contrôleur de vue au premier. J'ai parcouru de nombreuses questions similaires et je ne suis pas en mesure de les mettre en œuvre car je ne sais pas comment fonctionne le déroulement.

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

Cela transmettra les données à dataPassed dans le contrôleur de vue "viewControllerB". Dis, maintenant je veux passer des données de viewControllerB à dataRecieved dans ViewController. Comment est-ce que je peux faire ceci avec seulement dérouler segue et pas en utilisant délégué. Je suis assez nouveau pour Swift, j'aimerais une explication détaillée.

30
ebby94

Øyvind Hauge m'a battu à la même méthode de solution , mais comme j'avais déjà commencé avec une réponse plus détaillée, je vais l'ajouter également.


Supposons que vos deux contrôleurs de vue soient nommés comme suit:

  • Maître/point d'entrée: ViewController(vcA)
  • Vue secondaire: ViewControllerB(vcB)

Vous avez configuré la séquence à partir de (vcA) -> (vcB) comme vous l'avez fait dans votre exemple

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

L'étape quelque peu délicate suivante est que, en utilisant cette méthode, la séquence utilisée pour renvoyer les données à partir de (vcB) à (vcA) est également ajouté à la source de (vcA), en tant que @IBAction méthode (plutôt que, comme on pouvait s'y attendre, ajoutée à la source de (vcB)).

/* in ViewController.Swift */   

// ...

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

Vous vous connectez ensuite, disons, un bouton dans (vcB) à cette action de déroulement dans (vcA) via le manuel Exit segue in (vcB):

enter image description here

Ci-dessous, un exemple complet de passage de texte de (vcA) à (vcB); (éventuellement) modifier ce texte via un UITextField, renvoyant finalement le texte (éventuellement) modifié à (vcA).


(vcA) la source:

/* 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) source (notez que le délégué UITextFieldDelegate ici est uniquement utilisé pour muter "localement" la valeur de la propriété dataPassed, qui sera retournée à (vcA) et affecté à dataRecieved propriété de ce dernier)

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

Exemple d'exécution:

enter image description here

61
dfri

Voici comment je le ferais:

  1. Créez une sortie dans le contrôleur de vue 1, comme ceci:

    @IBAction func unwindToViewController1(segue: UIStoryboardSegue) {
    
       let foo = segue.sourceViewController.foo
    
       // TODO: Use foo in view controller 1
    }
    
  2. Connectez le contrôleur d'affichage 2 (le vc à partir duquel vous vous déroulez) comme indiqué ci-dessous. Faites glisser du cercle jaune dans vc2 vers "Quitter". L'IBAction du contrôleur de vue 1 devrait apparaître. Sélectionnez-le. enter image description here

  3. Maintenant, chaque fois que vous vous détendez du contrôleur de vue 2, le unwindToViewController1: la méthode dans le contrôleur de vue 1 sera appelée.

  4. C'est là que vous récupérerez la propriété que vous souhaitez du contrôleur de vue 2. Notez que vous devez convertir le segue.sourceViewController à votre sous-classe de contrôleur de vue personnalisé afin d'obtenir la bonne propriété.

11
oyvindhauge

Si votre application prend en charge iOS 9+, vous pouvez transmettre des données presque de la même manière que prepareForSegue, utilisez IStoryboardUnwindSegueSource qui a une propriété sender qui est exactement la même que la sender propriété dans prepare (pour segue: UIStoryboardSegue, sender: Any?) .

Comment l'utiliser:

  1. Créez une méthode unwindTo.

Remarque: La connexion de la méthode unwindTo est identique à @ Øyvind Hauge et @dfri expliquées dans leurs réponses.

  1. Dans le contrôleur de vue vers lequel vous souhaitez vous détendre, remplacez la méthode canPerformUnwindSegueAction (_: from: withSender:)
  2. Dans cette méthode, vérifiez si le type fromViewController est le type dont vous veniez
  3. Si c'est le cas, transtypez la propriété sender au type que vous avez envoyé et retournez true
  4. Sinon, retournez faux

Capture de code (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
}
1
OhadM