IOS - So programmieren Sie programmgesteuert mit Swift

185

Ich erstelle eine App, die das Facebook SDK zur Authentifizierung von Benutzern verwendet. Ich versuche, die Facebook-Logik in einer separaten Klasse zu konsolidieren. Hier ist der Code (der Einfachheit halber entfernt):

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

Ich verwende die obige Klassenmethode, um Änderungen des Sitzungsstatus zu überprüfen, und sie funktioniert einwandfrei.

F: Wie kann ich, sobald ich die Daten des Benutzers habe, innerhalb dieser benutzerdefinierten Klasse zur nächsten Ansicht übergehen?

BEARBEITEN: Um ganz klar zu sein, ich habe einen Segue mit einer Kennung im Storyboard und ich versuche einen Weg zu finden, einen Segue von einer Klasse durchzuführen, die nicht der View Controller ist

Shlomi Schwartz
quelle
2
Wie performSegue:?
HAT
Ja, aber der Code befindet sich nicht im viewController. Wie kann ich dies erreichen?
Shlomi Schwartz
In diesem Fall sollten Sie diese Arbeit (das Segueing) von dem Objekt, in dem Sie die Arbeit ausführen, an den Ansichtscontroller delegieren (über einen Abschlussblock oder eine Delegierungsmethode).
HAT
eine Nicht-Null-Layout-Ausnahme bekommen
Chris Hayes

Antworten:

340

Wenn Ihr Segue im Storyboard mit einer Segue-ID zwischen Ihren beiden Ansichten vorhanden ist, können Sie ihn einfach programmgesteuert aufrufen, indem Sie:

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

Für ältere Versionen:

performSegueWithIdentifier("mySegueID", sender: nil)

Sie könnten auch tun:

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

Oder wenn Sie sich in einem Navigationscontroller befinden:

self.navigationController?.pushViewController(nextViewController, animated: true)
Jérôme
quelle
7
Vielen Dank für die Antwort. Wie kann ich performSegueWithIdentifier von einer benutzerdefinierten Klasse aus aufrufen, die nicht die Ansicht ist?
Shlomi Schwartz
2
Wenn ich deine zweite Methode benutze. Wie übergebe ich Daten an die nächste Ansicht?
iamprem
2
Sie würden func prepareForSegue (Abschnitt: UIStoryboardSegue, Absender: AnyObject?) Verwenden und die Eigenschaften festlegen.
Lloyd Sargent
1
Beachten Sie, dass beim Aufrufen von performSequeWithIdentifer () eine Implementierung von prepareForSeque () in Ihrem aufrufenden Controller aufgerufen wird und Sie dort verschiedene Daten übergeben können. Tatsächlich ist der in prepareForSeque () empfangene Absenderparameter einfach das, was an den Absenderparameter in übergeben wird performSequeWithIdentifier ()
Timbo
1
Was ist, wenn der Abschnitt nicht im Storyboard vorhanden ist? Wenn Sie beispielsweise einen Übergang zu ViewController selbst erstellen möchten?
Scaryguy
20

Sie können NSNotification verwenden

Fügen Sie Ihrer benutzerdefinierten Klasse eine Post-Methode hinzu:

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

Fügen Sie Ihrem ViewController einen Beobachter hinzu:

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

Funktion in ViewController hinzufügen:

func methodOFReceivedNotication(notification: NSNotification){
    self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)
}
Rodrigo Otero
quelle
1
Bitte missbrauchen Sie solche Benachrichtigungen nicht. Verwenden Sie einen Delegaten und stellen Sie die Verbindung zwischen dem View Controller und Ihrer Klasse explizit her. Es ist nahezu unmöglich, den Kontrollfluss einer Benachrichtigung zu beobachten, da es mehrere Abonnenten geben kann und Instanzen nach Belieben abonnieren / abbestellen können.
uliwitness
17

Wenn Ihr Segue im Storyboard mit einer Segue-ID zwischen Ihren beiden Ansichten vorhanden ist, können Sie ihn einfach programmgesteuert aufrufen

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

Wenn Sie sich in der Navigationssteuerung befinden

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

Ich werde Sie für den zweiten Ansatz mit Navigations-Controller empfehlen.

Manish Mahajan
quelle
14

Sie können Segue wie folgt verwenden:

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

    }
}
Rudra
quelle
Vielen Dank für die Antwort, jedoch ist performSegueWithIdentifier eine viewController-Methode, und mein Code läuft in einer externen Klasse
Shlomi Schwartz
13

Swift 3 - Funktioniert auch mit SpriteKit

Sie können NSNotification verwenden .

Beispiel:

1.) Erstellen Sie einen Segue im Storyboard und nennen Sie die Kennung "Segue".

2.) Erstellen Sie eine Funktion in dem ViewController, von dem Sie wechseln.

func goToDifferentView() {

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

}

3.) In ViewDidLoad () Ihres ViewControllers wechseln Sie vom Erstellen des Beobachters.

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

Update - Als ich dies das letzte Mal verwendet habe, musste ich den .addObserverAufruf auf den folgenden Code ändern , um die Fehler auszuschalten.

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

4.) Fügen Sie in dem ViewController oder der Szene, zu der Sie wechseln, die Post-Methode hinzu, wo immer Sie den Übergang auslösen möchten.

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

Update - Als ich dies das letzte Mal verwendet habe, musste ich den .postAufruf auf den folgenden Code ändern , um die Fehler auszuschalten.

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

Was Sie tun möchten, ist für Unit-Tests wirklich wichtig. Grundsätzlich müssen Sie eine kleine lokale Funktion im View Controller erstellen. Nennen Sie die Funktion etwas, fügen Sie einfach die performSegueWithIndentifier.

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

Ändern Sie als Nächstes Ihre Utility-Klasse so FBManager, dass sie einen Initialisierer enthält, der ein Argument einer Funktion und eine Variable enthält, die die ViewController-Funktion enthält, die den Übergang ausführt.

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

(Mit dem Convenience-Init können Sie dies für Unit-Tests verwenden, ohne den Übergang auszuführen.)

Schließlich, wo Sie // todo: zur nächsten Ansicht übergehen ???, setzen Sie etwas in der Art von:

self.yourFunction()

In Ihren Unit-Tests können Sie es einfach wie folgt aufrufen:

let f = UtilClass()
f.doThatThing()

Dabei ist doThatThing Ihr fbsessionstatechange und UtilClassFBManager.

localFuncÜbergeben Sie für Ihren eigentlichen Code einfach (keine Klammern) an die FBManager-Klasse.

Rechnung
quelle
2

Das hat bei mir funktioniert.

Geben Sie dem View Controller in Ihrem Storyboard zunächst eine Storyboard-ID im Identitätsinspektor. Verwenden Sie dann den folgenden Beispielcode (stellen Sie sicher, dass Klasse, Storyboard-Name und Storyboard-ID mit den von Ihnen verwendeten übereinstimmen):

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)

Weitere Details finden Sie http://sketchytech.blogspot.com/2012/11/instantiate-view-controller-using.html besten Wünsche

amdan
quelle
1

Sie können dies mit der performSegueWithIdentifierFunktion tun .

Bildschirmfoto

Syntax :

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

Beispiel:

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

Eine andere Möglichkeit ist die Verwendung von Modal Segue

SCHRITT 1: Gehen Sie zum Storyboard und geben Sie dem View Controller eine Storyboard-ID . Wo Sie die Storyboard-ID ändern können, finden Sie rechts im Identitätsinspektor. Rufen wir die Storyboard-ID aufModalViewController

SCHRITT 2: Öffnen Sie den View Controller für den Absender (nennen wir ihn ViewController) und fügen Sie diesen Code hinzu

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

Beachten Sie, dass der View Controller, den wir öffnen möchten, auch aufgerufen wird ModalViewController

SCHRITT 3: Um ModalViewController zu schließen, fügen Sie dies hinzu

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

Das hat bei mir funktioniert:

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


    }

quelle