简体   繁体   English

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

[英]Displaying firebase child from user.uid to username in Swift 3

I 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.登录允许个人资料页面显示而没有错误,但在注册时,按下位于视图控制器底部的联系人按钮时应用程序崩溃,如下所示。

The process:过程:

User Signs Up:用户注册:

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

}

As in the signUp(), setUserInfo() is called, which contains images, and then calls saveUser()在 signUp() 中,调用 setUserInfo(),其中包含图像,然后调用 saveUser()

Save User保存用户

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)

}

Logs In登录

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

}

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.这里的问题在于 saveUser():目前,firebase 显示 user.uid,但我希望它显示用户的用户名。

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

With the above code, once the contacts button is pressed on the RidersVC, it crashes the app with error:使用上面的代码,一旦在 RidersVC 上按下联系人按钮,它就会使应用程序崩溃并出现错误:

fatal error: unexpectedly found nil while unwrapping an Optional value

on line 56 of MyProfileVC:在 MyProfileVC 的第 56 行:

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?关于如何让用户名显示为“骑手”的孩子而不是 user.uid 而不崩溃的任何想法?

MyProfileVC.swift 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 Database Structure: (how I want it to be) Firebase 数据库结构:(我想要的样子)

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

User.swift用户.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 structure - (the way it is now) 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"
     }
  }
}

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.此外,您可能可以删除所有 DispatchQueue 调用,因为 Firebase 为您完成了大部分繁重的工作,并且具有适当的代码结构,不需要它们。

1) A Swifty user class 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
    }
}

note that we are using the var uid of each user to identify them (their 'key')请注意,我们使用每个用户的 var uid 来识别他们(他们的“密钥”)

The structure that matches that class与该类匹配的结构

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"

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 作为键的子节点的 /users 节点中。

And some code that reads in uid_0, prints the uid and name.一些读取 uid_0 的代码打印 uid 和名称。 This code is a one-shot so it reads uid_0, but does NOT leave an observer attached to the node.此代码是一次性的,因此它读取 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)")
})

Now the Geofire node would like something like this现在 Geofire 节点会像这样

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.通常,最好将节点名称(键,它们是静态数据)与它们包含的动态数据分离。

With the structure in the initial question, imagine if 'europeanjunkie' changed his name to 'europeanjunkieDude'.根据最初问题中的结构,想象一下“europeanjunkie”是否将他的名字更改为“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.然后,您引用“europeanjunkie”的每个地方都必须更改 - 如果将其用作键,则必须读入、删除、更新和重写整个节点。

Using child keys created by Firebase, uid's and childByAutoId(), removes that issue.使用 Firebase 创建的子键、uid 和 childByAutoId() 可以消除该问题。

Hope that helps!希望有帮助!

In my opinion, if you want to query the username as the keyword.在我看来,如果要查询用户名作为关键字。 There are two possible ways to struct your dictionary.有两种可能的方法来构造你的字典。

First, use childByAutoId , username and userid will be at the same level, so you can get which value you like.首先,使用childByAutoId ,username 和 userid 将在同一级别,因此您可以获取您喜欢的值。

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

Second, make username as the child of riders.其次,将username设为骑手的孩子。 However, there would be tons of Mike.但是,会有很多迈克。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM