-1

When ViewController loads, the correct value gets printed. But when tried to print the same value with a UIButton, the print is nil

ViewController

var userEmail: String?

func userLoggedIn(data: String) {

    userEmail = data //sent from delagate
    print(userEmail) // successfully printed
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "loginView" {
        let loginViewController: LoginViewController = segue.destination as! LoginViewController
        loginViewController.delegate = self
    }
}

override func viewDidAppear(_ animated: Bool) {

   let isUserLoggedIn = UserDefaults.bool(UserDefaults.standard)(forKey: "isUserLoggedIn")

    if(!isUserLoggedIn) {
        self.performSegue(withIdentifier: "loginView", sender: self);
    }   
}

@IBAction func createCommunityTapped(_ sender: AnyObject) {

    let createCommunityController = self.storyboard?.instantiateViewController(withIdentifier: "CreateNewCommunity") as! CreateNewCommunity

    print ("now here ", userEmail) // prints nil
    createCommunityController.myEmail = userEmail
}

The userEmail value is being passed from LoginViewController via this section of code:

if(returnValue != "error") {

     self.delegate?.userLoggedIn(data: userEmail! )                
     UserDefaults.set(UserDefaults.standard)(true, forKey: "isUserLoggedIn");

     let mainPage = self.storyboard?.instantiateViewController(withIdentifier: "ViewController")
     let mainPageNav = UINavigationController(rootViewController: mainPage!)
     let appDelegate = UIApplication.shared.delegate
     appDelegate?.window??.rootViewController = mainPageNav 

     self.dismiss(animated: true, completion: nil)                
}

AppDelegate:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)        
    let isUserLoggedIn = UserDefaults.bool(UserDefaults.standard)(forKey: "isUserLoggedIn")

    if(!isUserLoggedIn) {

        let loginViewController = mainStoryboard.instantiateViewController(withIdentifier: "LoginViewController")            
        self.window?.rootViewController = loginViewController
        window!.makeKeyAndVisible()

    } else {

        let protectedPage = mainStoryboard.instantiateViewController(withIdentifier: "ViewController")            
        self.window?.rootViewController = protectedPage
        window!.makeKeyAndVisible()            
    }
    return true
}
RDowns
  • 651
  • 1
  • 10
  • 35
  • try to print, before you load the CreateNewCommunity – Dasem Oct 15 '16 at 19:04
  • It does print before I load the CreateNewCommunity, but I want it to print when I click the button so that I know the variable is getting to the function as I want to pass it on. – RDowns Oct 15 '16 at 19:08
  • Also, what happen when loginViewController Is being dismissed are you doing something there? – Dasem Oct 15 '16 at 19:15
  • The loginViewController is passing the value userEmail via the delegate straight into func userLoggedIn(data: String). I guess my issue is it's being trapped inside that function... How do I get the data out of there so I can use it in other functions within the class? – RDowns Oct 15 '16 at 19:29
  • You said that you have data passes to userEmail var in userLoggedIn(:String) function correctly then it should update your local variable userEmail correctly. Next then I would assume you tap on the button to call createCommunityTapped(:Anyobject). If that's the case then you should be able to do print(userEmail) in the first line in the function createCommunity fine. I don't see any problem ! – Ohmy Oct 15 '16 at 19:57
  • I tried moving the print ("now here ") line to the first line in the createCommunityTapped function but it did nothing. – RDowns Oct 15 '16 at 20:08
  • How do you return to this view controller from your login view controller? You must use an unwind segue. If you use a normal segue then you are moving to a new instance of this view controller and the property won't be set in this new instance since it wasn't the delegate. Using delegation isn't really necessary in this case, as you can acces the username from the source view controlller during the unwind process – Paulw11 Oct 15 '16 at 20:18
  • I've updated the question with the information you requested, thanks. I also don't know what an 'unwind segue' is, so I didn't know you could access the information from source using this kind of process? Cheers – RDowns Oct 15 '16 at 20:43
  • I think the problem is you are creating a new instance of ViewController , that why you are getting nil for userEmail, you need to work in a safe way, in general creat your vc in storyboard , in interface biulder and connect them with segue instead of doing, " instantiateViewController ". – Dasem Oct 15 '16 at 21:19
  • But would this account for printing the value for userEmail earlier on it the script? Remember its ONLY not printing from that function. It prints fine when the page loads. – RDowns Oct 15 '16 at 21:23
  • i can tell you one thing. your problem is not inside that code – David Seek Oct 15 '16 at 21:24
  • http://stackoverflow.com/questions/12561735/what-are-unwind-segues-for-and-how-do-you-use-them – Paulw11 Oct 15 '16 at 21:24
  • dude. in your viewcontroller class, is the userEmail variable changed anywhere else? or re-instantiated? – David Seek Oct 15 '16 at 21:29
  • The email prints because you are calling the delegate method in the first instance of the view controller, which is still in memory but is "behind" the login screen. You are then presenting a new instance of the view controller where the delegate method hasn't been called and the property isn't set – Paulw11 Oct 15 '16 at 21:29
  • In fact, you should be able to just get rid of the lines between the userDefaults.set and the dismiss – Paulw11 Oct 15 '16 at 21:32
  • So it sounds like I've approached this wrong in the way it first transfers the value using the delegate? Am I right in saying this should have been done in an unwind segue as suggest above? – RDowns Oct 15 '16 at 21:40
  • If you are using storyboards and segues then an unwind segue is the simplest approach – Paulw11 Oct 15 '16 at 22:12

1 Answers1

-1

The issue seems to lie in your Login view controller. You're passing the userEmail to your first instance of ViewController, then creating a new instance of ViewController and setting it as the root, which releases the first one. The first step should be to remove this code:

let mainPage = self.storyboard?.instantiateViewController(withIdentifier: "ViewController")
let mainPageNav = UINavigationController(rootViewController: mainPage!)
let appDelegate = UIApplication.shared.delegate
appDelegate?.window??.rootViewController = mainPageNav 

In your AppDelegate, you should set the root view controller to ViewController, and modally present the LoginViewController on top of it if the user is not logged in. Make sure to set the LoginViewController's delegate to ViewController. Then your login logic can be:

if(returnValue != "error") {
    self.delegate?.userLoggedIn(data: userEmail!)
    UserDefaults.standard.set(true, forKey: "isUserLoggedIn")

    self.dismiss(animated: true, completion: nil)                
}
Mark
  • 7,167
  • 4
  • 44
  • 68
  • I have thought about that as well, trying to debug his problem at the moment, but I get a print `now here Test` – David Seek Oct 15 '16 at 21:11
  • So even with his bad code, the value would be printed – David Seek Oct 15 '16 at 21:11
  • still printing nil with this answer – RDowns Oct 15 '16 at 21:18
  • Ah sorry, I wasn't aware you could print like that. I've updated my answer with what I believe is the actual problem. – Mark Oct 15 '16 at 21:43
  • I've just tried this code above - but this takes away the feature of the 'Protected' View Controller page from not showing upon startup. If I use this code you see the protected page before the LoginViewController pops over the top of it. – RDowns Oct 16 '16 at 08:27
  • You should be presenting the LoginViewController without animation. You'll need to do something like this if you want to dismiss the LoginViewController upon completion, and have ViewController underneath. The core of your problem, however, is that you're creating a new instance of ViewController and setting it as the root, losing any information you sent to the first ViewController. – Mark Oct 16 '16 at 13:24