IOS - Comment seguer par programmation en utilisant swift

185

Je crée une application qui utilise le SDK Facebook pour authentifier les utilisateurs. J'essaie de consolider la logique de Facebook dans une classe distincte. Voici le code (dépouillé pour plus de simplicité):

import Foundation

class FBManager {
    class func fbSessionStateChane(fbSession:FBSession!, fbSessionState:FBSessionState, error:NSError?){
        //... handling all session states
        FBRequestConnection.startForMeWithCompletionHandler { (conn: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in

            println("Logged in user: \n\(result)");

            let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
            let loggedInView: UserViewController = storyboard.instantiateViewControllerWithIdentifier("loggedInView") as UserViewController

            loggedInView.result = result;

            //todo: segue to the next view???
        }
    }
}

J'utilise la méthode de classe ci-dessus pour vérifier les changements d'état de session, et cela fonctionne bien.

Q: Une fois que j'ai les données de l'utilisateur, comment puis-je passer à la vue suivante à partir de cette classe personnalisée?

EDIT: juste pour être clair, j'ai une séquence avec un identifiant sur le storyboard, et j'essaie de trouver un moyen d'effectuer une séquence à partir d'une classe qui n'est pas le contrôleur de vue

Shlomi Schwartz
la source
2
Comme performSegue:?
HAS
Oui, mais le code n'est pas dans le viewController, comment puis-je y parvenir?
Shlomi Schwartz
Eh bien, dans ce cas, vous devez déléguer ce travail (la transition) de l'objet dans lequel vous effectuez le travail au contrôleur de vue (via un bloc de complétion ou une méthode de délégation).
HAS
obtenir une exception de mise en page non nil
Chris Hayes

Réponses:

340

Si votre segue existe dans le storyboard avec un identifiant de segue entre vos deux vues, vous pouvez simplement l'appeler par programme en utilisant:

performSegue(withIdentifier: "mySegueID", sender: nil)

Pour les anciennes versions:

performSegueWithIdentifier("mySegueID", sender: nil)

Vous pouvez également faire:

presentViewController(nextViewController, animated: true, completion: nil)

Ou si vous êtes dans un contrôleur de navigation:

self.navigationController?.pushViewController(nextViewController, animated: true)
Jérôme
la source
7
Merci pour la réponse, comment puis-je appeler performSegueWithIdentifier à partir d'une classe personnalisée qui n'est pas la vue?
Shlomi Schwartz
2
Si j'utilise votre deuxième méthode. Comment passer des données à la vue suivante?
iamprem
2
Vous utiliseriez func prepareForSegue (segue: UIStoryboardSegue, sender: AnyObject?) Et définissez les propriétés.
Lloyd Sargent
1
Notez que lors de l'appel de performSequeWithIdentifer (), une implémentation de prepareForSeque () dans votre contrôleur appelant sera appelée et vous pouvez y faire passer diverses données - en fait, le paramètre sender reçu dans prepareForSeque () est simplement ce qui est passé au paramètre sender dans performSequeWithIdentifier ()
timbo
1
Et si la segue n'existe pas dans le storyboard? Par exemple, si vous souhaitez créer une transition vers ViewController lui-même?
scaryguy
20

Vous pouvez utiliser NSNotification

Ajoutez une méthode de publication dans votre classe personnalisée:

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)

Ajoutez un observateur dans votre ViewController:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodOFReceivedNotication:", name:"NotificationIdentifier", object: nil)

Ajoutez une fonction dans votre ViewController:

func methodOFReceivedNotication(notification: NSNotification){
    self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)
}
Rodrigo Otero
la source
1
Veuillez ne pas abuser des notifications comme celle-ci. Utilisez un délégué et rendez explicite la connexion entre le contrôleur de vue et votre classe. Il est presque impossible d'observer le flux de contrôle d'une notification, car il peut y avoir plusieurs abonnés et les instances peuvent s'abonner / se désabonner à volonté.
uliwitness
17

Si votre segue existe dans le storyboard avec un identifiant de segue entre vos deux vues, vous pouvez simplement l'appeler par programme en utilisant

self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)

Si vous êtes dans le contrôleur de navigation

let viewController = YourViewController(nibName: "YourViewController", bundle: nil)        
self.navigationController?.pushViewController(viewController, animated: true)

Je vous recommanderai pour la deuxième approche en utilisant le contrôleur de navigation.

Manish Mahajan
la source
self.performSegue (withIdentifier: "yourIdentifierInStoryboard", expéditeur: self)
Rajneesh071
14

Vous pouvez utiliser segue comme ceci:

self.performSegueWithIdentifier("push", sender: self)
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    if segue.identifier == "push" {

    }
}
Rudra
la source
Merci pour la réponse, mais performSegueWithIdentifier est une méthode viewController, et mon code s'exécute dans une classe externe
Shlomi Schwartz
13

Swift 3 - Fonctionne également avec SpriteKit

Vous pouvez utiliser NSNotification .

Exemple:

1.) Créez une suite dans le storyboard et nommez l'identifiant "segue"

2.) Créez une fonction dans le ViewController à partir duquel vous effectuez la transition.

func goToDifferentView() {

    self.performSegue(withIdentifier: "segue", sender: self)

}

3.) Dans le ViewDidLoad () de votre ViewController à partir duquel vous faites la transition, créez l'observateur.

NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: "segue" as NSNotification.Name, object: nil)

Mise à jour - La dernière fois que j'ai utilisé cela, j'ai dû changer l' .addObserverappel au code suivant pour faire taire les erreurs.

NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: NSNotification.Name(rawValue: "segue"), object: nil)

4.) Dans le ViewController ou la scène vers laquelle vous effectuez la transition, ajoutez la méthode de publication à l'endroit où vous souhaitez que la séquence soit déclenchée.

NotificationCenter.default.post(name: "segue" as NSNotification.Name, object: nil)

Mise à jour - La dernière fois que j'ai utilisé cela, j'ai dû changer l' .postappel au code suivant pour faire taire les erreurs.

NotificationCenter.default.post(NSNotification(name: NSNotification.Name(rawValue: "segue"), object: nil) as Notification)
Timmy Sorensen
la source
Swift 3:NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: NSNotification.Name(rawValue: "segue"), object: nil)
Michael Samoylov
3

Ce que vous voulez faire est vraiment important pour les tests unitaires. Fondamentalement, vous devez créer une petite fonction locale dans le contrôleur de vue. Nommez la fonction n'importe quoi, incluez simplement leperformSegueWithIndentifier .

func localFunc() {
    println("we asked you to do it")
    performSegueWithIdentifier("doIt", sender: self)
}

Changez ensuite votre classe d'utilité FBManagerModifiez pour inclure un initialiseur qui prend un argument d'une fonction et une variable pour contenir la fonction de ViewController qui effectue la séquence.

public class UtilClass {

    var yourFunction : () -> ()

    init (someFunction: () -> ()) {
        self.yourFunction = someFunction
        println("initialized UtilClass")
    }

    public convenience init() {
        func dummyLog () -> () {
            println("no action passed")
        }
        self.init(dummyLog)
    }

    public func doThatThing() -> () {
        // the facebook login function
        println("now execute passed function")
        self.yourFunction()
        println("did that thing")
    }
}

(L'init de commodité vous permet de l'utiliser dans les tests unitaires sans exécuter la séquence.)

Enfin, là où vous avez // todo: segue à la vue suivante ???, mettez quelque chose du genre:

self.yourFunction()

Dans vos tests unitaires, vous pouvez simplement l'invoquer comme:

let f = UtilClass()
f.doThatThing()

où doThatThing est votre fbsessionstatechange et UtilClass est FBManager.

Pour votre code réel, passez simplement localFunc(sans parenthèses) à la classe FBManager.

Facture
la source
2

Cela a fonctionné pour moi.

Tout d'abord, donnez au contrôleur de vue de votre storyboard un ID de storyboard dans l'inspecteur d'identité. Utilisez ensuite l'exemple de code suivant (en vous assurant que la classe, le nom du storyboard et l'ID du storyboard correspondent à ceux que vous utilisez):

let viewController:
UIViewController = UIStoryboard(
    name: "Main", bundle: nil
).instantiateViewControllerWithIdentifier("ViewController") as UIViewController
// .instantiatViewControllerWithIdentifier() returns AnyObject!
// this must be downcast to utilize it

self.presentViewController(viewController, animated: false, completion: nil)

Pour plus de détails, voir http://sketchytech.blogspot.com/2012/11/instantiate-view-controller-using.html meilleurs voeux

amdan
la source
1

Vous pouvez faire cette chose en utilisant performSegueWithIdentifierfunction.

Capture d'écran

Syntaxe:

func performSegueWithIdentifier(identifier: String, sender: AnyObject?)

Exemple :

 performSegueWithIdentifier("homeScreenVC", sender: nil)
Jayprakash Dubey
la source
1

Une autre option consiste à utiliser la séquence modale

ÉTAPE 1: Accédez au storyboard et attribuez au contrôleur de vue un ID de storyboard . Vous pouvez trouver où modifier l'ID du storyboard dans l'inspecteur d'identité sur la droite. Permet d'appeler l'ID du storyboardModalViewController

ÉTAPE 2: Ouvrez le contrôleur de vue `` expéditeur '' (appelons-le ViewController) et ajoutez-y ce code

public class ViewController {
  override func viewDidLoad() {
    showModalView()
  }

  func showModalView() {
    if let mvc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ModalViewController") as? ModalViewController {
      self.present(mvc, animated: true, completion: nil)
    }
  }
}

Notez que le contrôleur de vue que nous voulons ouvrir est également appelé ModalViewController

ÉTAPE 3: Pour fermer ModalViewController, ajoutez-y

public class ModalViewController {
   @IBAction func closeThisViewController(_ sender: Any?) {
      self.presentingViewController?.dismiss(animated: true, completion: nil)
   }
}
aphoe
la source
0

Cela a fonctionné pour moi:

//Button method example
 @IBAction func LogOutPressed(_ sender: UIBarButtonItem) {

        do {
            try Auth.auth().signOut()
            navigationController?.popToRootViewController(animated: true)

        } catch let signOutError as NSError {
          print ("Error signing out: %@", signOutError)
        }


    }

la source