将firebase子项从user.uid显示到Swift 3中的用户名

拥有My Profile的视图控制器。 登录允许配置文件页面无错误地显示,但在注册时,按下位于视图控制器底部的联系人按钮时应用程序崩溃,如下所示。

过程:

用户注册:

func signUp(_ email: String, usersname: String, password: String, data: Data!, loginHandler: LoginHandler?) { FIRAuth.auth()?.createUser(withEmail: email, password: password, completion: { (user, error) in if error != nil { // Show error to user self.handleFirebaseErrors(err: error as! NSError, loginHandler: loginHandler) } else { // success creating user if user?.uid != nil { // if there is a valid user id // Store user to database self.setUserInfo(user, usersname: usersname, email: email, password: password, data: data!) // Log In the user self.login(email: email, password: password, loginHandler: loginHandler) } } }) } 

与signUp()一样,调用setUserInfo(),其中包含图像,然后调用saveUser()

保存用户

 func saveUser(_ user: FIRUser!, usersname: String, email: String, password: String) { // Create the user dictionary info let userInfo = ["email": user.email!, "password": password, "usersname": usersname, "uid": user.uid, "photoUrl": String(describing: user.photoURL!)] // create user reference let userRef = DataService.Instance.dbRef.child("riders").child(user.uid) // Save the user info in the database userRef.setValue(userInfo) } 

登录

 func login(email: String, password: String, loginHandler: LoginHandler?) { FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: { (user, error) in if error != nil { self.handleFirebaseErrors(err: error as! NSError, loginHandler: loginHandler) } else { loginHandler?(nil, nil) } }) } 

这里的问题是在saveUser()中:此时,firebase显示了user.uid,但我希望它显示用户的用户名。

 let userRef = DataService.Instance.dbRef.child("riders").child(usersname) 

使用上面的代码,一旦在RidersVC上按下了联系人按钮,它就会崩溃应用程序并出现错误:

 fatal error: unexpectedly found nil while unwrapping an Optional value 

在MyProfileVC的第56行:

 let imageUrl = String(user.photoUrl) 

任何想法,如何我可以将用户名显示为“骑手”的孩子而不是user.uid而不会崩溃? 任何帮助,将不胜感激。

MyProfileVC.swift

 if FIRAuth.auth()?.currentUser == nil { let vc = UIStoryboard(name: "Rider", bundle: nil).instantiateViewController(withIdentifier: "Login") present(vc, animated: true, completion: nil) } else { dbRef.child("riders/\(FIRAuth.auth()!.currentUser!.uid)").observe(.value, with: { (snapshot) in DispatchQueue.main.async(execute: { let user = User(snapshot: snapshot) self.username.text = user.usersname self.email.text = FIRAuth.auth()?.currentUser?.email let imageUrl = String(user.photoUrl) 

Firebase数据库结构:(我希望如何)

 { "riders" : { "rider 1" : { "email" : "rider1@me.com", "password" : "whatever", "photoUrl" : "https://firebasestorage.googleapis.com/...", "usersname" : "rider 1" } } } 

User.swift

 struct User { let usersname: String! let email: String! let password: String! let photoUrl: String! var ref: FIRDatabaseReference? var key: String init(snapshot: FIRDataSnapshot) { key = snapshot.key ref = snapshot.ref let snapshotValueUsersname = snapshot.value as? NSDictionary usersname = snapshotValueUsersname?["usersname"] as? String let snapshotValueEmail = snapshot.value as? NSDictionary email = snapshotValueEmail?["email"] as? String let snapshotValuePass = snapshot.value as? NSDictionary password = snapshotValuePass?["password"] as? String let snapshotValuePhoto = snapshot.value as? NSDictionary photoUrl = snapshotValuePhoto?["photoUrl"] as? String } 

Firebase结构 – (现在的方式)

 { "drivers" : { "RideRequests" : { "europeanjunkie" : { "active" : true, "latitude" : "45.267", "longitude" : "-66.059", "userId" : "5c17ByRJljZFcM703Vqn5eSFwYJ3", "username" : "europeanjunkie" } } }, "riders" : { "5c17ByRJljZFcM703Vqn5eSFwYJ3" : { "email" : "europeanjunkie@me.com", "password" : "whatever", "photoUrl" : "https://firebasestorage.googleapis.com", "uid" : "5c17ByRJljZFcM703Vqn5eSFwYJ3", "usersname" : "europeanjunkie" } } } 

这里有一些需要考虑的事情 – 一点点,部分或全部都可能让你朝着正确的方向前进。 此外,您可以删除所有DispatchQueue调用,因为Firebase会为您完成大部分繁重工作,并且使用正确的代码结构,不需要它们。

1)Swifty用户类

 class UserClass { var usersname = "" var email = "" var password = "" var photoUrl = "" var uid = "" init(withSnapshot: FIRDataSnapshot) { let dict = withSnapshot.value as! [String:AnyObject] uid = withSnapshot.key usersname = dict["usersname"] as! String email = dict["email"] as! String password = dict["password"] as! String photoUrl = dict["photoUrl"] as! String } } 

请注意我们正在使用每个用户的var uid来识别它们(它们的“键”)

与该类匹配的结构

 users uid_0 email: "bill@email.com" password: "myPassword" photoUrl: "http://www.url.com" usersname: "Bill" uid_1 email: "leroy@email.com" password: "aPassword" photoUrl: "http://www.anotherUrl.com" usersname: "Leroy" 

再次注意,用户及其相关信息存储在每个子节点的/ users节点中,该节点具有用户uid作为密钥。

一些读入uid_0的代码会打印出uid和name。 此代码是一次性的,因此它读取uid_0,但不会将观察者附加到节点。

 let userRef = rootRef.child("users/uid_0") userRef.observeSingleEvent(of: .value, with: { snapshot in let aUser = UserClass(withSnapshot: snapshot) print("uid \(aUser.uid) has name \(aUser.usersname)") }) 

现在Geofire节点想要这样的东西

 user_locations uid_0 //geofire data uid_1 //geofire data 

所以现在用户节点和它们的位置之间存在直接关联。

通常,将节点名称(键,即静态数据)与它们包含的数据(即动态数据)取消关联是个好主意。

根据最初问题的结构,想象一下’europeanjunkie’是否将他的名字改为’europeanjunkieDude’。 然后必须更改您引用的每个地方’europeanjunkie’ – 如果它被用作密钥,则必须读入,删除,更新和重写整个节点。

使用Firebase,uid和childByAutoId()创建的子密钥可以消除该问题。

希望有所帮助!

在我看来,如果你想查询用户名作为关键字。 构造字典有两种可能的方法。

首先,使用childByAutoId ,用户名和用户ID将处于同一级别,这样您就可以获得自己喜欢的值。

 { "riders" : { "-KQaU9lVcUYzIo52LgmN" : { "email" : "rider1@me.com", "password" : "whatever", "photoUrl" : "https://firebasestorage.googleapis.com/...", "usersname" : "rider 1", "userid" : "rider 1" } } } 

其次,将username作为骑手的孩子。 然而,迈克会有很多。

 { "riders" : { "username" : { "email" : "rider1@me.com", "password" : "whatever", "photoUrl" : "https://firebasestorage.googleapis.com/...", "userid" : "rider 1" } } }