IOS - Cómo segmentar programáticamente usando swift

185

Estoy creando una aplicación que usa el SDK de Facebook para autenticar a los usuarios. Estoy tratando de consolidar la lógica de Facebook en una clase separada. Aquí está el código (despojado por simplicidad):

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

Estoy usando el método de clase anterior para verificar los cambios de estado de la sesión, y funciona bien.

P: Una vez que tengo los datos del usuario, ¿cómo puedo pasar a la siguiente vista desde esta clase personalizada?

EDITAR: para ser claros, tengo un segue con identificador en el guión gráfico, y estoy tratando de encontrar una manera de realizar un segue de una clase que no sea el controlador de vista

Shlomi Schwartz
fuente
2
Al igual que performSegue:?
TIENE
Sí, pero el código no está en viewController, ¿cómo puedo lograr esto?
Shlomi Schwartz
Bueno, en ese caso, debe delegar ese trabajo (la segmentación) del objeto en el que realiza el trabajo al controlador de vista (a través de un bloque de finalización o un método de delegado).
TIENE
obteniendo una excepción de diseño no nulo
Chris Hayes

Respuestas:

340

Si su segue existe en el guión gráfico con un identificador de segue entre sus dos vistas, puede llamarlo mediante programación usando:

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

Para versiones anteriores:

performSegueWithIdentifier("mySegueID", sender: nil)

También puedes hacer:

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

O si estás en un controlador de navegación:

self.navigationController?.pushViewController(nextViewController, animated: true)
Jérôme
fuente
77
Gracias por la respuesta, ¿cómo puedo llamar a performSegueWithIdentifier desde una clase personalizada que no es la vista?
Shlomi Schwartz
2
Si uso tu segundo método. ¿Cómo pasar datos a la siguiente vista?
iamprem
2
Usaría func prepareForSegue (segue: UIStoryboardSegue, remitente: AnyObject?) Y establecería las propiedades.
Lloyd Sargent
1
Tenga en cuenta que cuando llame a performSequeWithIdentifer (), se llamará a una implementación de prepareForSeque () en su controlador de llamadas y podrá pasar varios datos allí; de hecho, el parámetro del remitente recibido en prepareForSeque () es simplemente lo que se pasa al parámetro del remitente en performSequeWithIdentifier ()
timbo
1
¿Qué pasa si el segmento no existe en el guión gráfico? Por ejemplo, si desea crear un segue a ViewController en sí mismo?
scaryguy
20

Puedes usar NSNotification

Agregue un método de publicación en su clase personalizada:

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

Agregue un observador en su ViewController:

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

Añadir función en su ViewController:

func methodOFReceivedNotication(notification: NSNotification){
    self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)
}
Rodrigo Otero
fuente
1
No abuses de notificaciones como esta. Use un delegado y haga explícita la conexión entre el controlador de vista y su clase. Es casi imposible observar el flujo de control de una notificación, porque podría haber múltiples suscriptores, y las instancias pueden suscribirse / darse de baja a voluntad.
uliwitness
17

Si su segue existe en el guión gráfico con un identificador de segue entre sus dos vistas, puede llamarlo mediante programación usando

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

Si estás en el controlador de navegación

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

Te recomendaré para un segundo enfoque usando el controlador de navegación.

Manish Mahajan
fuente
self.performSegue (withIdentifier: "yourIdentifierInStoryboard", remitente: self)
Rajneesh071
14

Puedes usar segue así:

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

    }
}
Rudra
fuente
Gracias por la respuesta, sin embargo, performSegueWithIdentifier es un método viewController, y mi código se ejecuta en una clase externa
Shlomi Schwartz el
13

Swift 3 : también funciona con SpriteKit

Puede usar NSNotification .

Ejemplo:

1.) Cree una secuencia en el guión gráfico y nombre el identificador "segue"

2.) Cree una función en el ViewController del que está segue.

func goToDifferentView() {

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

}

3.) En el ViewDidLoad () de su ViewController está segue de crear el observador.

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

Actualización : la última vez que usé esto tuve que cambiar la .addObserverllamada al siguiente código para silenciar los errores.

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

4.) En el ViewController o Scene al que está siguiendo, agregue el Método de publicación donde desee que se desencadene la segue.

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

Actualización : la última vez que usé esto tuve que cambiar la .postllamada al siguiente código para silenciar los errores.

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

Lo que quiere hacer es realmente importante para las pruebas unitarias. Básicamente, necesita crear una pequeña función local en el controlador de vista. Asigne un nombre a la función, solo incluya el performSegueWithIndentifier.

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

A continuación, cambie su clase de utilidad FBManagerpara incluir un inicializador que tome un argumento de una función y una variable para contener la función ViewController que realiza la segue.

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

(El init de conveniencia le permite usar esto en pruebas unitarias sin ejecutar el segue).

Finalmente, donde tienes // todo: pasar a la siguiente vista ???, pon algo en la línea de:

self.yourFunction()

En sus pruebas unitarias, simplemente puede invocarlo como:

let f = UtilClass()
f.doThatThing()

donde doThatThing es su fbsessionstatechange y UtilClasses FBManager.

Para su código real, simplemente pase localFunc(sin paréntesis) a la clase FBManager.

Cuenta
fuente
2

Esto funcionó para mí.

En primer lugar, proporcione al controlador de vista en su storyboard una ID de Storyboard dentro del inspector de identidad. Luego use el siguiente código de ejemplo (asegurándose de que la clase, el nombre del guión gráfico y el ID del guión gráfico coincidan con los que está usando):

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)

Para obtener más detalles, consulte http://sketchytech.blogspot.com/2012/11/instantiate-view-controller-using.html mis mejores deseos

amdan
fuente
1

Puedes hacer esto usando la performSegueWithIdentifierfunción.

Captura de pantalla

Sintaxis:

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

Ejemplo:

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

Otra opción es usar modal segue

PASO 1: vaya al guión gráfico y dele al controlador de vista una identificación del guión gráfico . Puede encontrar dónde cambiar la ID del guión gráfico en el Inspector de identidad a la derecha. Llamemos al ID del guión gráficoModalViewController

PASO 2: Abra el controlador de vista 'remitente' (llamémoslo ViewController) y agregue este código

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

Tenga en cuenta que el controlador de vista que queremos abrir también se llama ModalViewController

PASO 3: Para cerrar ModalViewController, agréguele esto

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

Esto funcionó para mí:

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


    }

fuente