IOS - Jak programowo segregować za pomocą szybkiego

185

Tworzę aplikację, która używa Facebook SDK do uwierzytelniania użytkowników. Próbuję skonsolidować logikę Facebooka w osobnej klasie. Oto kod (uproszczony dla uproszczenia):

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

Używam powyższej metody klasy do sprawdzania zmian stanu sesji i działa dobrze.

P: Jak mam dane użytkownika, jak mogę przejść do następnego widoku z tej niestandardowej klasy?

EDYCJA: żeby być jasnym, mam sekwencję z identyfikatorem w serii ujęć i próbuję znaleźć sposób na wykonanie segue z klasy, która nie jest kontrolerem widoku

Shlomi Schwartz
źródło
2
Jak performSegue:?
MA
Tak, ale kodu nie ma w widokuController, jak mogę to osiągnąć?
Shlomi Schwartz
Cóż, w takim przypadku powinieneś delegować tę pracę (segregowanie) z obiektu, w którym wykonujesz pracę, do kontrolera widoku (za pomocą bloku zakończenia lub metody delegowania).
MA
uzyskiwanie wyjątku układu non-zero
Chris Hayes

Odpowiedzi:

340

Jeśli Twój segue istnieje w serii ujęć z identyfikatorem segue między Twoimi widokami, możesz po prostu wywołać go programowo, używając:

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

W przypadku starszych wersji:

performSegueWithIdentifier("mySegueID", sender: nil)

Możesz także:

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

Lub jeśli jesteś w kontrolerze nawigacyjnym:

self.navigationController?.pushViewController(nextViewController, animated: true)
Jérôme
źródło
7
Dzięki za odpowiedź, jak mogę wywołać performSegueWithIdentifier z niestandardowej klasy, która nie jest widokiem?
Shlomi Schwartz
2
Jeśli użyję twojej drugiej metody. Jak przekazać dane do następnego widoku?
iamprem,
2
Użyłbyś func preparForSegue (segue: UIStoryboardSegue, sender: AnyObject?) I ustawiłeś właściwości.
Lloyd Sargent
1
Uwaga: podczas wywoływania metody performSequeWithIdentifer () zostanie wywołana implementacja preparForSeque () w kontrolerze wywołującym i można tam przesyłać różne dane - w rzeczywistości parametr sender otrzymany w preparForSeque () jest po prostu przekazywany do parametru nadawcy w performSequeWithIdentifier ()
timbo
1
Co jeśli segue nie istnieje w serii ujęć? Na przykład, jeśli chcesz utworzyć segment do samego ViewController?
scaryguy
20

Możesz użyć NSNotification

Dodaj metodę postu do swojej klasy niestandardowej:

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

Dodaj obserwatora do swojego ViewController:

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

Dodaj funkcję w tobie ViewController:

func methodOFReceivedNotication(notification: NSNotification){
    self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)
}
Rodrigo Otero
źródło
1
Nie nadużywaj takich powiadomień. Użyj delegata i wyraź jawne połączenie między kontrolerem widoku a klasą. Niemożliwe jest obserwowanie przepływu kontrolnego powiadomienia, ponieważ może być wielu subskrybentów, a instancje mogą subskrybować / anulować subskrypcję do woli.
uliwitness
17

Jeśli Twój segue istnieje w serii ujęć z identyfikatorem segue między Twoimi widokami, możesz po prostu wywołać go programowo za pomocą

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

Jeśli jesteś w kontrolerze nawigacyjnym

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

Polecę cię do drugiego podejścia przy użyciu kontrolera nawigacyjnego.

Manish Mahajan
źródło
self.performSegue (withIdentifier: "yourIdentifierInStoryboard", nadawca: self)
Rajneesh071
14

Możesz użyć segue w następujący sposób:

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

    }
}
Rudra
źródło
Dzięki za odpowiedź, jednak performSegueWithIdentifier jest metodą viewController, a mój kod działa w klasie zewnętrznej
Shlomi Schwartz
13

Swift 3 - Działa również z SpriteKit

Możesz użyć NSNotification .

Przykład:

1.) Utwórz segue w serii ujęć i nazwij identyfikator „segue”

2.) Utwórz funkcję w ViewController, z którego segregujesz.

func goToDifferentView() {

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

}

3.) W ViewDidLoad () kontrolera ViewController oddzielasz się od utworzenia obserwatora.

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

Aktualizacja - ostatnim razem, gdy go użyłem, musiałem zmienić .addObserverwywołanie na następujący kod, aby wyciszyć błędy.

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

4.) W ViewController lub scenie, do której segregujesz, dodaj metodę Post wszędzie tam, gdzie chcesz, aby została uruchomiona segue.

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

Aktualizacja - ostatnim razem, gdy go użyłem, musiałem zmienić .postwywołanie na następujący kod, aby wyciszyć błędy.

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

To, co chcesz zrobić, jest naprawdę ważne dla testów jednostkowych. Zasadniczo musisz utworzyć małą funkcję lokalną w kontrolerze widoku. Nazwij funkcję cokolwiek, po prostu dołącz performSegueWithIndentifier.

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

Następnie zmień klasę użyteczności, tak FBManageraby zawierała inicjator, który pobiera argument funkcji i zmienną do przechowywania funkcji ViewController wykonującej 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")
    }
}

(Wygodna inicjacja pozwala na użycie tego w testach jednostkowych bez wykonywania segue.)

Na koniec, gdzie masz // todo: segue do następnego widoku ???, umieść coś wzdłuż linii:

self.yourFunction()

W testach jednostkowych możesz po prostu wywołać go jako:

let f = UtilClass()
f.doThatThing()

gdzie doThatThing to twoja fbsessionstatechange i UtilClassjest FBManager.

W celu uzyskania rzeczywistego kodu wystarczy przekazać localFunc(bez nawiasów) do klasy FBManager.

Rachunek
źródło
2

To zadziałało dla mnie.

Przede wszystkim nadaj kontrolerowi widoku w swojej serii ujęć identyfikator serii ujęć w inspektorze tożsamości. Następnie użyj następującego przykładowego kodu (upewniając się, że klasa, nazwa scenorysu i identyfikator scenorysu odpowiadają tym, którego używasz):

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)

Aby uzyskać więcej informacji, zobacz http://sketchytech.blogspot.com/2012/11/instantiate-view-controller-using.html najlepsze życzenia

amdan
źródło
1

Możesz to zrobić za pomocą performSegueWithIdentifierfunkcji.

Zrzut ekranu

Składnia:

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

Przykład:

 performSegueWithIdentifier("homeScreenVC", sender: nil)
Jayprakash Dubey
źródło
1

Inną opcją jest użycie modalnego segue

KROK 1: Przejdź do scenorysu i nadaj kontrolerowi widoku identyfikator scenorysu . Gdzie możesz zmienić identyfikator scenorysu w Inspektorze tożsamości po prawej stronie. Zadzwoń do ID scenorysuModalViewController

KROK 2: Otwórz kontroler widoku „nadawca” (nazwijmy go ViewController) i dodaj do niego ten kod

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

Pamiętaj, że nazywany jest również kontroler widoku, który chcemy otworzyć ModalViewController

KROK 3: Aby zamknąć ModalViewController, dodaj to do niego

public class ModalViewController {
   @IBAction func closeThisViewController(_ sender: Any?) {
      self.presentingViewController?.dismiss(animated: true, completion: nil)
   }
}
aphoe
źródło
0

To działało dla mnie:

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


    }

źródło