Swift segue not working? - ios

My Swift segue is not working at all and isn't throwing any errors. The breakpoint shows me that the app lands on this line but nothing happens:
self.performSegueWithIdentifier("SignupSegue", sender: self)
The code block is a login form with Facebook:
if let accessToken: FBSDKAccessToken = FBSDKAccessToken.currentAccessToken() {
PFFacebookUtils.logInInBackgroundWithAccessToken(result.token, block: {
(user: PFUser ? , error : NSError ? ) - > Void in
if user!.isNew {
self.performSegueWithIdentifier("SignupSegue", sender: self)
} else {
self.navigateToInGame(true)
}
})
}
Here's the segue function it should call, but doesn't even get to it:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "SignupSegue") {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("SignUpViewController")
self.showViewController(vc, sender: self)
}
}
Any ideas?

Generally, any UI updating has to be in main thread. I think the block for PFFacebookUtils.logInInBackgroundWithAccessToken is still in the background state in above situation. Maybe trigger the showViewController in dispatch_async(dispatch_get_main_queue(), {}) and see if there is any difference.
dispatch_async(dispatch_get_main_queue(), {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("SignUpViewController")
self.showViewController(vc, sender: self)
})

Ok. I just tried it out. Hope you did all the things regarding StoryBoard Reference.
Me too had the same issue with performSegueWithIdentifier.
Example:
Let take two storyboard main and signup.
1) In main.storyboard create a storyboard reference. Set the storyboardId in the Storyboard Reference as signup and the referencedId as the storyboardId of the scene(viewController) which is in signup.storyboard. Look at this link for a clear picture Storyboard to Storyboard
2) Set the segue identifier between viewController and Storyboard Reference in main.storyboard
3) Since I faced the same problem with performSegueWithIdentifier, I replaced it with shouldPerformSegueWithIdentifier.
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
if(identifier == "segue_identifier"){
// segue_identifier is the viewController and storyBoard Reference segue identifier.
print("hello")
}
return true;
}
Let me know if you find any issues. It did work for me.

Performing a segue leads to present a new view controller.You don't need to and can't create and show view controller in prepareForSegue.It will look like:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "SignupSegue") {
let vc = segue.destinationViewController
}
}

Swift 3 solved:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "SignupSegue") {
DispatchQueue.main.async {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "SignUpViewController")
self.show(vc, sender: self)
}
}
}

You can try this ...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "SignupSegue") {
if let destination = segue.destination as? SignUpViewController {
...
}
}
}

The closest I can get to overcome same problem for myself:
Made trigger var segueLogin : Bool = false with initialised value in the Class.
When PFFacebookUtils gets needed values for segue, change trigger to true:
PFFacebookUtils.logInInBackground(withReadPermissions: permissions) {
(user: PFUser?, error: Error?) -> Void in
if let user = user {
if user.isNew {
print("User signed up and logged in through Facebook!")
self.segueLogin = true
} else {
print("User logged in through Facebook!")
self.segueLogin = true
}
} else {
print("Uh oh. The user cancelled the Facebook login.")
self.loginCancelledLabel.alpha = 1
}
}
Then added code to viewDidAppear class. Realised it starts everytime PFFacebookUtils complete. So it checks if returned value is true and performs segue after successful PFFacebookUtils session:
override func viewDidAppear(_ animated: Bool) {
if segueLogin == true {
self.performSegue(withIdentifier: "segueSingup", sender: self)
}
}

Related

PersonalityQuiz guided app in swift fundamentals

I've got problem with some additional challenges. I need to filter an array of type Question by some property and then pass it into next View Controller via segue. I've done this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let sender = sender as? UIButton else {return}
if sender == quiz3Button {
let vc = segue.destination as? QuestionViewController
vc?.correctQuestions = questions.filter { question in
return question.quiz == .animals
}
} else if sender == quiz4Button {
let vc = segue.destination as? QuestionViewController
vc?.correctQuestions = questions.filter { question in
return question.quiz == .cars
}
}
}
#IBAction func quiz3ButtonTapped(_ sender: UIButton) {
performSegue(withIdentifier: "animals", sender: sender)
}
#IBAction func quiz4Button(_ sender: UIButton) {
performSegue(withIdentifier: "cars", sender: sender)
}
Filtration works but it doesn't pass value to next View Controller. I declared variable in QuestionViewControler like that
var correctQuestions: [Question] = []
But when I need to access it I get error "Index out of range". So I figured that its empty..
Segues been made from buttons to VC
Ok. I've got it. The NavigationController was the problem here. Added into function push through NC and it worked ;) so closed I think
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let sender = sender as? UIButton else {return}
if sender == quiz3Button {
let destinationViewController = segue.destination as? UINavigationController
let questionViewController = destinationViewController?.viewControllers.first as! QuestionViewController
questionViewController.correctQuestions = questions.filter { questions in
return questions.quiz == .animals
}
} else if sender == quiz4Button {
let destinationViewController = segue.destination as? UINavigationController
let questionViewController = destinationViewController?.viewControllers.first as! QuestionViewController
questionViewController.correctQuestions = questions.filter { questions in
return questions.quiz == .cars
}
}
}

Prepare for segue function using SW revealer

I'm trying to send a bool through a SWRevealViewControllerSeguePushController using prepareForSegue function, but it doesn't even gives me a response.
This code is in my side menu viewController (sw_rear). I've also set an identifier on the segue and this is my code so far:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "registerSegue" {
if let loginVC = segue.destination as? LoginVC {
print("Set it as true")
loginVC.registerActivated = true
}
} else {
if let loginVC = segue.destination as? LoginVC {
print("set it as false")
loginVC.registerActivated = false
}
}
}
I'm not receiving any output to the console with this code. Is there another good way to send data between ViewControllers using SWRevealViewControllerSeguePushController on a segue?
Thanks!

prepareForSegue called before performSegue

I am trying to perform a segue that passes a number of variables to the next view including one variable, currentID, which is retrieved from a parse database. performSegue should not be called until after currentID has been set to the currentID downloaded from the database. However, when I run the code, currentID ends up being an empty string when it is passed to the next view.
Here is my code called by the Button:
#IBAction func submitButtonPressed(_ sender: Any) {
let point = PFGeoPoint(latitude:0.0, longitude:0.0)
let testObject = PFObject(className: "Person")
testObject["inputAmount"] = inputAmount
testObject["outputAmount"] = outputAmount
testObject["inputCurrency"] = inputCurrency
testObject["outputCurrency"] = outputCurrency
testObject["location"] = point
testObject.saveInBackground { (success, error) -> Void in
// added test for success 11th July 2016
if success {
print("Object has been saved.")
self.currentID = String(describing: testObject.objectId!)
if(self.currentID != ""){
self.performSegue(withIdentifier: "mainToListSegue", sender: self)
}
} else {
if error != nil {
print (error)
} else {
print ("Error")
}
}
}
}
And here is the prepareForSegue method:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let listViewController = (segue.destination as! UINavigationController).viewControllers[0] as! ListViewController
listViewController.inputCurrency = inputCurrency
listViewController.outputCurrency = outputCurrency
listViewController.inputAmount = inputAmount
listViewController.outputAmount = outputAmount
listViewController.currentID = currentID
listViewController.cellContent = cellContent
}
To achieve your needs, you MUST connect your segue between viewcontrollers, and not from UIButton to viewcontroller.
Every time you need to prepare your segue before calling it, this is the procedure:
Then, name it and use delegate method
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mySegue" {
}
}
For navigating from one controller to another, connect your segue from view controller instead of from the button and it will work.

Perform segue on completion of web service call Swift3

I am trying to perform a segue on successful login in swift 3. Once my web service returns success message I want to perform segue. I am trying the same in the following manner:
DispatchQueue.main.sync(execute: {
print("Login successful")
self.performSegue(withIdentifier: "goToTimerPage", sender: self)
})
My log is printing fine.
Please help me with this. I am new to web services.
use like this
DispatchQueue.main.sync(execute: {
print("Login successful")
self.performSegue(withIdentifier: "goToTimerPage", sender: self)
})
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToTimerPage" {
//present your view controller or do some code
}
Simple way for navigation.
Setup your didFinishLaunchingWithOptions like this way.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let storyboard :UIStoryboard
if UIDevice.currentDevice().userInterfaceIdiom == .Pad{
storyboard = UIStoryboard(name: "Main_iPad", bundle: nil)
}
else{
storyboard = UIStoryboard(name: "Main", bundle: nil)
}
let navigationController:UINavigationController = storyboard.instantiateInitialViewController() as! UINavigationController
let objLoginViewController:UIViewController = storyboard.instantiateViewControllerWithIdentifier("ID_LoginViewController") as! LoginViewController
navigationController.viewControllers = [objLoginViewController]
if self.window != nil {
self.window!.rootViewController = navigationController
}
return true
}
Call this function once get successful response.
self.redirectToNewViewcontroller()
Code for redirectToNewViewcontroller function
func redirectToNewViewcontroller()
{
let objNewViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ID_NewViewController") as? NewViewController
self.navigationController?.pushViewController(objNewViewController!, animated: true)
}
simply make sure you embed your view controller in a navigation controller
the source view controller not the destination view controller

Swift - how to transfer from one view controller to another?

Back to my first swift app, I'm doing the sign in/sign up part, and basically the design with the view controllers so far are:
Welcome screen (sign in/sign up buttons) - Sign in - Sign up - Main Program
I got to the part where in the sign up view controllers, if the user misses one of the required field blanks and they click the button "submit", they will be prompted and back to the current view controller (sign up) to fill the missing fields. Now I want to set that when all the fields are filled, what line of code can I use so when they click the button "submit" it will head back to the welcome screen, so they can sign in afterwards?
Similarly, I got all the the part to check if the user enters correct user name and password, so when they entered the wrong info, they will be prompted and hack to the current view controller (sign in), and how can I do so if they entered the correct user name - password, it will head to the main program view controller (the 4th one)
If what I said above is confusing, I'll post my current controllers and the related code in here. Anyone has any idea? Again, this is my first program so it'd mean very much if I can get some helps from you. Thank you for reading.
An example on how to do it:
import UIKit
class WelcomeVC: UIViewController {
//make it IBAction or call it from IBAction
func singInButtonPressed(){
performSegueWithIdentifier("sign in", sender: self)
}
//make it IBAction or call it from IBAction
func singUPButtonPressed(){
performSegueWithIdentifier("sign up", sender: self)
}
}
class SignUPVC: UIViewController {
#IBOutlet var userNameField:UITextField!
#IBOutlet var passwordField:UITextField!
//make it IBAction or call it from IBAction
func submit(){
if checkValidity() {
presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
}
}
func checkValidity() ->Bool{
if !userNameField.text!.isEmpty{
if !passwordField.text!.isEmpty {
return true
} else {
//do something to inform passwordfield is missing
}
} else{
//username field is missing
}
return false
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "sign in" {
if let sINvc = segue.destinationViewController.contentViewController as? SignInVC{
sINvc.username = userNameField.text
sINvc.password = passwordField.text
//and pass more of the other info you gathered in this vc
}
}
}
}
class SignInVC: UIViewController {
#IBOutlet var userNameField:UITextField!{
didSet {
if username != nil { userNameField.text = username }
}
}
#IBOutlet var passwordField:UITextField! {
didSet {
if password != nil { passwordField.text = password }
}
}
var password:String?
var username:String?
//make it IBAction or call it from IBAction
func signInPressed(){
if !userNameField.text!.isEmpty && !passwordField.text!.isEmpty {
performSegueWithIdentifier("Main page", sender: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Main page"{
//your preparation
}
}
}
//this extension is helpful to avoid typing this everytime there is nav vc in your way of segueing
extension UIViewController{
var contentViewController: UIViewController {
if self is UINavigationController{
if let cvc = (self as! UINavigationController).visibleViewController { return cvc }
}
return self
}
}
simple way to transfer one view to another in swift is this given below:-
let storyboard = UIStoryboard(name: "Main", bundle: nil)
//in "Main" your storyboard name
let secondViewController = storyboard.instantiateViewControllerWithIdentifier("LoginPage") as! UIViewController
//in place of Login Page your storyboard identifier name
navigationController?.pushViewController(secondViewController, animated: true)
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let mainTabBar = storyBoard.instantiateViewController(withIdentifier: "MainTabBar") as! UITabBarController
self.navigationController?.pushViewController(mainTabBar, animated: true)
works for me. thanks! update for the swift 3.1 and Xcode 8.3.2

Resources