将firebase子项从user.uid显示到Swift 3中的用户名 [英] displaying firebase child from user.uid to username in Swift 3
问题描述
拥有My Profile的视图控制器。登录允许配置文件页面无错误地显示,但在注册时,按下位于视图控制器底部的联系人按钮时应用程序崩溃,如下所示。
Have a view controller for My Profile. Logging in allows the profile page to appear without errors but when signing up, app crashes when pressing the contacts button located at bottom of view controller as seen below.
流程:
用户注册:
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()
As in the signUp(), setUserInfo() is called, which contains images, and then calls 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,但我想要它显示用户的用户名。
The problem here is in saveUser(): At the moment, firebase shows the user.uid but I want it to show the username of the user.
let userRef = DataService.Instance.dbRef.child("riders").child(usersname)
使用上面的代码,一旦在RidersVC上按下联系人按钮,它就会导致应用程序崩溃,错误:
With the above code, once the contacts button is pressed on the RidersVC, it crashes the app with error:
fatal error: unexpectedly found nil while unwrapping an Optional value
$ b MyProfileVC第56行
$ b
:
on line 56 of MyProfileVC:
let imageUrl = String(user.photoUrl)
我是如何将用户名显示为骑手的孩子而不是用户的任何想法。没有它崩溃?任何帮助将不胜感激。
Any ideas as how I can get the username to be displayed as the child of "riders" instead of the user.uid without it crashing? Any help would be appreciated.
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数据库结构:(我希望如何)
Firebase Database Structure: (how I want it to be)
{
"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结构 - (现在的方式)
Firebase structure - (the way it is now)
{
"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会为您完成大部分繁重工作,并且使用正确的代码结构,不需要它们。
Here's some stuff to consider - a little, some or all may get you headed in the right direction. Also, you can probably remove all of the DispatchQueue calls as Firebase does most of the heavy lifting for you, and with proper code structure, they are not needed.
1)一个Swifty用户类
1) A Swifty user class
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用户识别它们(它们的'键')
note that we are using the var uid of each user to identify them (their 'key')
与该类匹配的结构
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作为键。
Notice again the users and their associated info are stored within the /users node in each child node that has that users uid as the key.
并且一些读入uid_0的代码打印uid和名称。此代码是一次性的,因此它读取uid_0,但不会将观察者附加到节点。
And some code that reads in uid_0, prints the uid and name. This code is a one-shot so it reads uid_0, but does NOT leave an observer attached to the node.
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节点想要这样的东西
Now the Geofire node would like something like this
user_locations
uid_0
//geofire data
uid_1
//geofire data
所以现在之间存在直接关联用户节点及其位置。
So now there is a direct correlation between the users node and their location.
通常,将节点名称(密钥,即静态数据)与其包含的数据(动态)取消关联是个好主意。
In general, it's a good idea to disassociate node names (keys, which are static data) from the data they contain, which is dynamic.
根据最初问题中的结构,想象一下'europeanjunkie'是否将他的名字改为'europeanjunkieDude'。然后必须更改您引用的每个地方'europeanjunkie' - 如果它被用作密钥,则必须读入,删除,更新和重写整个节点。
With the structure in the initial question, imagine if 'europeanjunkie' changed his name to 'europeanjunkieDude'. Every place you reference 'europeanjunkie' would then have to be changed - and if it's used as a key, the entire node would have to be read in, deleted, updated, and re-written.
使用由Firebase,uid和childByAutoId()创建的子密钥,可以解决该问题。
Using child keys created by Firebase, uid's and childByAutoId(), removes that issue.
希望有所帮助!
这篇关于将firebase子项从user.uid显示到Swift 3中的用户名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!