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?
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
}
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.
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)
}
}
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é!
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.