拥有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"
}
}
}
答案 0 :(得分:1)
这里有一些需要考虑的事情 - 一点点,部分或全部可能让你朝着正确的方向前进。此外,您可以删除所有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'。然后,您引用'eurojunkie'的每个地方都必须更改 - 如果它被用作密钥,则必须读入,删除,更新和重写整个节点。
使用Firebase,uid和childByAutoId()创建的子密钥可以解决该问题。
希望有所帮助!
答案 1 :(得分:0)
在我看来,如果你想查询用户名作为关键字。构建词典有两种可能的方法。
首先,使用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"
}
}
}