web-dev-qa-db-fra.com

Variables d'accès à partir du délégué d'application dans View Controller

Je suis en train de mettre en œuvre la connexion à Google sur mon application et je dois accéder à l'ID utilisateur et au prénom/nom. Les variables stockant ces données sont dans le délégué d'application. J'ai cherché sur Internet à l'intérieur et à l'extérieur pour savoir comment faire cela dans Swift 3, et il n'y a absolument rien.

Voici le délégué de l'application (au moins la partie qui compte):

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

Dans View Controller, j'appelle le délégué de l'application et j'essaie de recevoir les données, mais le message d'erreur suivant s'affiche: "Le membre de l'instance 'ID utilisateur' ne peut pas être utilisé sur le 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()
}

}

J'ai également essayé de permuter AppDelegate avec délégué dans le = AppDelegate.userID mais cela me donne la même erreur. Que se passe-t-il?

5

Le message d'erreur vous a dit property initializers run before 'self' is available.

Peut-être devriez-vous l'initialiser dans 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
}
17
AlvinZhu

AppDelegate est la classe. Ce que vous voulez, c'est l'instance de AppDelegate qui est le délégué de votre application. En outre, vous ne pouvez pas utiliser la constante delegate que vous avez déclarée pour définir les valeurs des autres membres d'instance, car il s'agit également d'un membre d'instance. 

J'aime implémenter une fonction dans AppDelegate comme ceci:

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

Et puis je peux simplement l'appeler d'ailleurs comme suit:

let firstName = AppDelegate.shared().givenName

Une autre option serait de définir les valeurs de ces propriétés à l'aide de la propriété delegate que vous avez définie, mais de le faire ultérieurement, comme dans viewDidLoad, comme le suggère la réponse d'Alvin.

6
Samantha

Mise à jour: vous n'avez pas besoin d'accéder à Appdelegate pour GoogleSignIn. Utilisez le code suivant dans votre action de bouton

 @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)
    }
}
1
phantom

Vous pouvez également créer quelque chose de similaire à UIApplication.shared .... Ensuite, vous devez ajouter ceci à AppDelegates:

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

ou quelque chose comme ça:

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

Que vous ayez la syntaxe Swift 3.x :)

À votre santé!

0
jLaszczewski

Tu ne devrais jamais le faire. Vous devez disposer d'une abstraction appropriée pour gérer la connexion. Le délégué de l'application doit être une classe privée. Quel est l'intérêt d'utiliser cet état partagé? La connexion à Google dispose de méthodes pratiques pour le gérer et les informations d'identification de l'utilisateur ne doivent pas être enregistrées dans le délégué de l'application. Vous pouvez utiliser une classe ou une base de données si nécessaire.

0
Myrenkar