I'm creating an app that uses the Facebook SDK to authenticate users. I'm trying to consolidate the facebook logic in a separate class. Here is the code (stripped for simplicity):
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???
}
}
}
I'm using the above class method to check session state changes, and it works fine.
Q: Once I have the user's data, how can I segue to the next view from within this custom class?
Just to be clear, I have a segue with identifier on the storyboard, and I'm trying to find a way to perform a segue from a class which is not the view controller
performSegue:
?
If your segue exists in the storyboard with a segue identifier between your two views, you can just call it programmatically using:
performSegue(withIdentifier: "mySegueID", sender: nil)
For older versions:
performSegueWithIdentifier("mySegueID", sender: nil)
You could also do:
presentViewController(nextViewController, animated: true, completion: nil)
Or if you are in a Navigation controller:
self.navigationController?.pushViewController(nextViewController, animated: true)
If your segue exists in the storyboard with a segue identifier between your two views, you can just call it programmatically using
self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)
If you are in Navigation controller
let viewController = YourViewController(nibName: "YourViewController", bundle: nil)
self.navigationController?.pushViewController(viewController, animated: true)
I will recommend you for second approach using navigation controller.
You can use NSNotification
Add a post method in your custom class:
NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)
Add an observer in your ViewController:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodOFReceivedNotication:", name:"NotificationIdentifier", object: nil)
Add function in you ViewController:
func methodOFReceivedNotication(notification: NSNotification){
self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)
}
You can use segue like this:
self.performSegueWithIdentifier("push", sender: self)
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if segue.identifier == "push" {
}
}
Swift 3 - Also works with SpriteKit
You can use NSNotification.
Example:
1.) Create a segue in the storyboard and name the identifier "segue"
2.) Create a function in the ViewController you are segueing from.
func goToDifferentView() {
self.performSegue(withIdentifier: "segue", sender: self)
}
3.) In the ViewDidLoad() of your ViewController you are segueing from create the observer.
NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: "segue" as NSNotification.Name, object: nil)
Update - Last time I used this I had to change the .addObserver
call to the following code to silence the errors.
NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: NSNotification.Name(rawValue: "segue"), object: nil)
4.) In the ViewController or Scene you are segueing to, add the Post Method wherever you want the segue to be triggered.
NotificationCenter.default.post(name: "segue" as NSNotification.Name, object: nil)
Update - Last time I used this I had to change the .post
call to the following code to silence the errors.
NotificationCenter.default.post(NSNotification(name: NSNotification.Name(rawValue: "segue"), object: nil) as Notification)
NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: NSNotification.Name(rawValue: "segue"), object: nil)
There are already great answers above, i'd like to put little focus on preparation before performing segue.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is YourDestinationVC {
let vc = segue.destination as? YourDestinationVC
// "label" and "friends" are part of destinationVC
vc?.label = "someText"
vc?.friends = ["John","Mike","Garry"]
}
Once your are done with data that you want to pass on to your destinationVC then perform your segue at an appropriate place. You can set "IdentifierOfDestinationVC" in StoryBoard Identity inspector in StoryBoard ID field
performSegue(withIdentifier: "IdentifierOfDestinationVC", sender: nil)
What you want to do is really important for unit testing. Basically you need to create a small local function in the view controller. Name the function anything, just include the performSegueWithIndentifier
.
func localFunc() {
println("we asked you to do it")
performSegueWithIdentifier("doIt", sender: self)
}
Next change your utility class FBManager
to include an initializer that takes an argument of a function and a variable to hold the ViewController's function that performs the 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")
}
}
(The convenience init allows you to use this in unit testing without executing the segue.)
Finally, where you have //todo: segue to the next view???, put something along the lines of:
self.yourFunction()
In your unit tests, you can simply invoke it as:
let f = UtilClass()
f.doThatThing()
where doThatThing is your fbsessionstatechange and UtilClass
is FBManager.
For your actual code, just pass localFunc
(no parenthesis) to the FBManager class.
This worked for me.
First of all give the view controller in your storyboard a Storyboard ID inside the identity inspector. Then use the following example code (ensuring the class, storyboard name and story board ID match those that you are using):
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)
For more details see http://sketchytech.blogspot.com/2012/11/instantiate-view-controller-using.html best wishes
You can do this thing using performSegueWithIdentifier
function.
https://i.stack.imgur.com/31nGG.png
Syntax :
func performSegueWithIdentifier(identifier: String, sender: AnyObject?)
Example :
performSegueWithIdentifier("homeScreenVC", sender: nil)
Another option is to use modal segue
STEP 1: Go to the storyboard, and give the View Controller a Storyboard ID. You can find where to change the storyboard ID in the Identity Inspector on the right. Lets call the storyboard ID ModalViewController
STEP 2: Open up the 'sender' view controller (let's call it ViewController
) and add this code to it
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)
}
}
}
Note that the View Controller we want to open is also called ModalViewController
STEP 3: To close ModalViewController, add this to it
public class ModalViewController {
@IBAction func closeThisViewController(_ sender: Any?) {
self.presentingViewController?.dismiss(animated: true, completion: nil)
}
}
This worked for me:
//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)
}
}
Success story sharing