Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access variables from App Delegate in View Controller

Tags:

ios

swift

swift3

I am implementing Google sign in on my app and I need to access the User ID and first/last name. The variables storing that data are in the App Delegate. I have searched the internet inside and out looking for how to do this in Swift 3, and there is absolutely nothing.

Here's the App Delegate (at least the part that matters):

class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {

var window: UIWindow?
var databaseRef: FIRDatabaseReference!

var userID = String()
var givenName = String()
var familyName = String()

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

    // Use Firebase library to configure APIs
    FIRApp.configure()

    GIDSignIn.sharedInstance().clientID = FIRApp.defaultApp()?.options.clientID
    GIDSignIn.sharedInstance().delegate = self

    return true
}

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {

    return GIDSignIn.sharedInstance().handle(url,
                                             sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as? String,
                                             annotation: options[UIApplicationOpenURLOptionsKey.annotation])
}

func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {

    if let error = error {
        print(error.localizedDescription)
        return
    }
    print("User signed into Google")

    let authentication = user.authentication
    let credential = FIRGoogleAuthProvider.credential(withIDToken: (authentication?.idToken)!,
                                                      accessToken: (authentication?.accessToken)!)

    FIRAuth.auth()?.signIn(with: credential) { (user, error) in
        print("User Signed Into Firebase")


        self.databaseRef = FIRDatabase.database().reference()

        self.databaseRef.child("user_profiles").child(user!.uid).observeSingleEvent(of: .value, with: { (snapshot) in

            let snapshot = snapshot.value as? NSDictionary

            if(snapshot == nil)
            {
                self.databaseRef.child("user_profiles").child(user!.uid).child("name").setValue(user?.displayName)
                self.databaseRef.child("user_profiles").child(user!.uid).child("email").setValue(user?.email)
            }


        })

    }

    userID = user.userID
    givenName = user.profile.givenName
    familyName = user.profile.familyName


    continueToWallet()
}

In the View Controller, I am calling the App delegate and trying to receive the data, but it gives me an error saying, "Instance member 'User ID' cannot be used on type 'AppDelegate'"

class addToWalletController: UIViewController {

var ID = String()

let delegate = UIApplication.shared.delegate as! AppDelegate
let user = AppDelegate.userID
let firstName = AppDelegate.givenName
let lastName = AppDelegate.familyName

override func viewDidLoad() {
    super.viewDidLoad()
}

}

I have also tried switching AppDelegate with delegate in the =AppDelegate.userID but it gives me the same error. What's going on?

like image 904
Matthew McDonnell Avatar asked Mar 01 '17 03:03

Matthew McDonnell


People also ask

How do I present a view controller from another view controller?

Start a segue from any object that implements an action method, such as a control or gesture recognizer. You may also start segues from table rows and collection view cells. Right-click the control or object in your current view controller. Drag the cursor to the view controller you want to present.


4 Answers

AppDelegate is the class. What you want is the instance of AppDelegate that is your application's delegate. In addition, you can't use the delegate constant you've declared to set the values of other instance members because it is also an instance member itself.

I like to implement a function in AppDelegate like this:

static func shared() -> AppDelegate {
    return UIApplication.shared.delegate as! AppDelegate
}

And then I can just call it from elsewhere like so:

let firstName = AppDelegate.shared().givenName

Another option would be to set the values of these properties using the delegate property you have defined, but do it later such as in viewDidLoad, such as Alvin's answer suggests.

like image 128
Samantha Avatar answered Oct 02 '22 23:10

Samantha


You can also made something similar to UIApplication.shared.... Than you have to add this to AppDelegates:

open class var shared: AppDelegate {
    get {
        return UIApplication.shared.delegate as! AppDelegate
    }
}

or something like this:

public class var shared: AppDelegate {
    return UIApplication.shared.delegate as! AppDelegate
}

Than you have Swift 3.x syntax :)

Cheers!

like image 44
jLaszczewski Avatar answered Oct 02 '22 23:10

jLaszczewski


The error message have told you property initializers run before 'self' is available.

Maybe you should initialize it in viewDidLoad

let delegate = UIApplication.shared.delegate as! AppDelegate
var user: String?
var firstName: String?
var lastName: String?

override func viewDidLoad() {
    super.viewDidLoad()

    user = delegate.userID
    firstName = delegate.givenName
    lastName = delegate.familyName
}
like image 32
AlvinZhu Avatar answered Oct 02 '22 22:10

AlvinZhu


Update: You don't need to access Appdelegate for GoogleSignIn. Use following code in your button action

 @IBAction func loginWithGoogle(_ sender: Any) {
    GIDSignIn.sharedInstance().uiDelegate = self
    GIDSignIn.sharedInstance().signIn()
    //Be sure that you are signed-in
    if(GIDSignIn.sharedInstance().hasAuthInKeychain()){
        print("Signed-in")
        //Use currentUser attribute.
        print(GIDSignIn.sharedInstance().currentUser.profile.email)
    }
}
like image 23
ozanonurtek Avatar answered Oct 02 '22 23:10

ozanonurtek