Firebase数据库帮助 - Swift [英] Firebase database help - Swift

查看:204
本文介绍了Firebase数据库帮助 - Swift的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我已经完成了所有的实际应用程序。我只需要设置后端。我认为Firebase是最好的解决方案,因为Parse不再是一件事情。我想要的是:

具有配置文件的用户 - 这些配置文件可以通过添加好友查看,但只能由实际配置文件所有者编辑(写入)。




所以我通读了Firebase Docs,但仍然无法真正弄清楚如何做到这一点。他们只有一个Swift应用程序的例子,不做任何类似的事情,而一个Obj C的叽叽喳喳,甚至不会建立。他们的所有文档仍然有Swift的println,只是让我觉得它不是经常更新。




有没有人有这样的好例子/教程?我一直试图寻找的东西,但没有什么是足够相似的,我想要的东西。我更关注如何为每个用户设置数据库,并在Swift中实际使用Firebase。

解决方案

正如我在你的问题的评论中写到的,这个答案是基于我们在真正的社交应用程序 Impether using Swift + Firebase



数据结构



假设你要为单个用户存储以下信息:


  • 电子邮件
  • li> 用户名

  • 关注 - 特定用户关注的人数

  • $ b

    由于在Firebase中一切都存储了JSON对象,因此可以将上述结构存储在节点下路径如 users / $ userId ,其中 $ userId 是每个注册用户创建的Firebase用户UID使用简单的电子邮件/密码Firebase授权。

    Firebase电子邮件/密码授权在其文档中进行了描述:
    https://www.firebase.com/docs/ios/guide/user-auth.html
    https://www.firebase.com/docs/ios/guide /login/password.html



    请注意,这里有Obj-C和Swift代码片段。我发现Firebase文档真的很棒,因为它在构建我们的应用程序时帮助了我很多。



    为了达到这个目的,我们假设我们拥有用户名 jack 和Firebase用户UID等于 jack_uid (实际上这将是由Firebase生成的字符串)。



    然后,此用户的示例数据将存储在路径 users / jack_uid 下,可能如下所示:

      {
    email:jack@example.com,
    用户名:jack,
    name:Jack,
    followers:8,
    following:11,
    avatar_url:http://yourstoragesystem.com/avatars/jack .jpg,
    bio:Blogger,YouTuber,
    }



    < Firebase电子邮件/密码授权的效果非常好,但说实话,如果用户想登录应用程序,使用用户名称比在注册帐户时给他的电子邮件好得多。



    为了做到这一点,我们决定存储从用户名到用户ID的映射。这个想法是,如果用户在登录表单中输入他的用户名和密码,我们使用该映射来检索他的用户ID,然后我们尝试使用他的用户ID和提供的密码签署他。



    映射可以存储在路径 username_to_uid 下,如下所示:

    <$ p
    sample_username_1:firebase_generated_userid_1,
    sample_username_2:firebase_generated_userid_2,
    ...
    jack: jack_uid,
    sample_username_123:firebase_generated_userid_123
    }

    一个配置文件可能看起来像这样,一旦一个新帐户的注册成功(这段代码非常接近我们在生产中使用的确切代码),就完成了:

     func createProfile(uid:String,email:String,
    username:String,avatarUrl:String,
    successBlock:() - > Void,errorBlock: - > ; Void){

    //用户数据节点的路径
    let userDataPath =/ users / \(uid)

    //用户用户名的路径到uid映射
    let usernameToUidDataPath =/ username_to_uid / \(username)

    //你想拥有代表用户数据的JSON对象
    //我们使用我们的用户Swift结构来做
    //但是你可以在这里创建一个原始的JSON对象。
    // name,avatarUrl,bio,followers和以下是
    //用默认值初始化
    let user = User(uid:uid,username:username,name:,
    avatarUrl:avatarUrl,bio:,
    followers:0,如下所示:0)

    //从用户实例
    var userData = user生成一个JSON对象。 serialize()
    //我们添加电子邮件到JSON数据,因为我们不存储
    //直接在我们的对象中
    userData [email] = email

    //我们使用fanoutObject同时更新用户数据
    //和用户名到uid的映射
    //这是非常方便的,因为
    //写都是成功或出现任何错误时,
    //不写任何内容,所以您可以避免在数据库中出现
    //不一致的情况。你可以阅读更多关于这个技巧
    //这里:https://www.firebase.com/blog/2015-10-07-how-to-keep-your-data-consistent.html

    var fanoutObject = [String:AnyObject]()
    fanoutObject [userDataPath] = userData
    fanoutObject [usernameToUidDataPath] = uid

    let ref = Firebase(url: https://YOUR-FIREBASE-URL.firebaseio.com/images)
    ref.updateChildValues(fanoutObject,withCompletionBlock:{
    err,snap
    if err nil {
    //如果没有错误,调用成功回调
    successBlock()
    } else {
    //在这里处理错误
    errorBlock()
    }






    $ b除此之外,你可能想要为每个用户存储他的追随者列表和他遵循的单独的用户列表。这可以通过像 followers / jack_uid 这样的路径存储用户标识符来完成,例如它可以是这样的:

      {
    firebase_generated_userid_4:true,
    firebase_generated_userid_14:true
    }
    pre>

    这是我们在应用程序中存储多组值的方式。它非常方便,因为它是真正的用户来更新它,并检查是否有一些价值。

    为了统计追随者的数量,我们把这个计数器放到用户的数据直接。这使得阅读柜台非常有效。然而,更新这个计数器需要使用事务性写入,这个想法几乎和我在这里的答案一样:通过Firebase在Swift中使用Upvote / Downvote系统

    读取/写入权限



    你的问题的一部分是如何处理你存储的数据的权限。好消息是,Firebase在这里特别好。如果您转到Firebase信息中心,则会出现一个名为安全与规则的选项卡,这是您控制数据权限的地方。

    Firebase规则的优点在于它们是声明式的,这使得它们非常易于使用和维护。但是,在纯JSON中编写规则并不是最好的主意,因为当您想要将某些原子规则组合到一个更大的规则中时,要控制它们非常困难,或者您的应用程序简单增长,而且Firebase数据库中存储的数据越来越多。幸运的是,Firebase团队编写了Bolt,这是一种可以非常轻松地编写所有需要的规则的语言。首先,我建议阅读有关Security的Firebase文档,尤其是节点权限如何影响其子对象的权限。然后,你可以在这里看看Bolt:

    https://www.firebase.com/docs/security/bolt/guide.html
    https://www.firebase.com/blog/2015-11-09-introducing-the-bolt-compiler .html
    https:// github。 com / firebase / bolt / blob / master / docs / guide.md



    例如,我们使用规则来管理用户数据, p>

      //全局助手
    isCurrentUser(userId){
    auth!= null&& auth.uid == userId;
    }

    isLogged(){
    auth!= null;
    }

    //自定义类型,你可以扩展它们
    //如果你想要
    类型UserId extends String;
    类型用户名扩展字符串;
    类型AvatarUrl扩展字符串;
    类型电子邮件扩展字符串;

    类型用户{
    avatar_url:AvatarUrl,
    bio:字符串,
    电子邮件:电子邮件,
    追随者:数字,
    以下:数字,
    name:String,
    username:用户名,
    }

    //用户数据规则
    path / users / {$ userId}是User {
    write(){isCurrentUser($ userId)}
    read(){isLogged()}
    }

    //用户的关注者规则
    //用户的特定
    //用户遵循的规则类似于
    path / followers / {$ userId} {
    read(){isLogged()}
    }

    path / followers / {$ userId} / {$ followerId}是布尔值{
    create(){isCurrentUser($ followerId)&& this == true}
    delete(){isCurrentUser($ followerId)}
    }

    //使用用户名的规则
    路径/ username_to_uid {
    read(){true}
    }

    path / username_to_uid / {$ username}是UserId {
    create(){isCurrentUser(this)}
    }

    底线是您使用 Bolt Simulator 选项卡中的工具来测试您的规则。
    $ b



    对我来说,Firebase是一个实现您所需系统的好工具。不过,我建议先从简单的功能开始,学习如何使用Firebase。使用像Instagram这样的功能来实现社交应用程序是一个相当大的挑战,特别是如果你想要做到这一点正确的话:)很容易把所有的功能放在那里,而Firebase使得它相对容易,但我建议要有耐心这里。

    另外,花点时间和投资编写工具。例如,我们有两个独立的Firebase数据库,一个用于生产,另一个用于测试,如果您想要高效编写单元和UI测试,这非常重要。

    另外,我建议从一开始就建立权限规则。以后再添加它们可能是诱人的,但也是相当的压倒性的。

    最后但并非最不重要的,请关注Firebase博客。他们定期发布,你可以与他们的最新功能和更新日期 - 这是我学会了如何使用扇出技术使用并发写入。

    so I already finished all of the actual app for this. I just need to setup the backend. I figured Firebase was the best solution since Parse is no longer a thing. What I wanted was:

    Users with profiles - These profiles can be viewed by added friends but only edited (written) to by the actual profile owner.


    So I read through the Firebase Docs and still cannot really figure out how to do this. They only have 1 Swift application example that does not do anything similar and the one Obj C twitter one, will not even build. All of their docs still have println for Swift which just makes me think it is not updated frequently.


    Does anyone have any good examples / tutorials of this? I keep trying to search for things but nothing is as similar enough to what I want. I am more looking on how to setup the db for each user and access it rather actually using Firebase in Swift.

    解决方案

    As I wrote in my comment to your question, this answer is based on what we do in a real social app Impether using Swift + Firebase.

    Data structure

    Let's assume that you want to store the following information for a single user:

    • email
    • username
    • name
    • followers - number of people who follow a particular user
    • following - number of people who a particular user follows
    • avatar_url - url of their avatar
    • bio - some additional text

    Since in Firebase everything is stored a JSON objects, you can store the above structure under node with path like users/$userId, where $userId is Firebase User UID which is created for each registered user if you use simple email/password Firebase authorization.

    Firebase email/password authorization is described in their docs: https://www.firebase.com/docs/ios/guide/user-auth.html https://www.firebase.com/docs/ios/guide/login/password.html

    Notice that there are both Obj-C and Swift snippets. I find Firebase documentation really great as it helped me a lot when I was building our app.

    For the purpose of this answer let's assume that we have user with username jack and Firebase User UID equal to jack_uid (in reality this will be a string generated by Firebase).

    Then an example data for this user will be store under a path users/jack_uid and can look like this:

    {
      "email" : "jack@example.com",
      "username" : "jack",
      "name" : "Jack",
      "followers" : 8,
      "following" : 11,
      "avatar_url" : "http://yourstoragesystem.com/avatars/jack.jpg",
      "bio" : "Blogger, YouTuber",
    }
    

    Firebase email/password authorization works really well, but let's be honest, if user wants to sign in into the app, it's a lot better for him to use his username than his email he gave while he registering his account.

    In order to do that, we decided to store a mapping from usernames to user ids. The idea is that if user inputs his username and password in a login form, we use that mapping to retrieve his user id and then we try to sign him in using his user id and provided password.

    The mapping can be stored for example under a path username_to_uid and looks like this:

    { 
       "sample_username_1": "firebase_generated_userid_1",
       "sample_username_2": "firebase_generated_userid_2",
       ...
       "jack": "jack_uid",
       "sample_username_123": "firebase_generated_userid_123"
    }
    

    Then creating a profile may looks like this and it's done as soon as registration of a new account was successful (this snippet is very close to the exact code we use in the production):

    func createProfile(uid: String, email: String,
                       username: String, avatarUrl: String,
                       successBlock: () -> Void, errorBlock: () -> Void) {
    
        //path to user data node
        let userDataPath = "/users/\(uid)"
    
        //path to user's username to uid mapping
        let usernameToUidDataPath = "/username_to_uid/\(username)"
    
        //you want to have JSON object representing user data
        //and we do use our User Swift structures to do that
        //but you can just create a raw JSON object here.
        //name, avatarUrl, bio, followers and following are
        //initialized with default values
        let user = User(uid: uid, username: username, name: "",
                        avatarUrl: avatarUrl, bio: "",
                        followers: 0, following: 0)
    
        //this produces a JSON object from User instance
        var userData = user.serialize()
        //we add email to JSON data, because we don't store
        //it directly in our objects
        userData["email"] = email
    
        //we use fanoutObject to update both user data
        //and username to uid mapping at the same time
        //this is very convinient, because either both
        //write are successful or in case of any error,
        //nothing is written, so you avoid inconsistencies
        //in you database. You can read more about that technique
        //here: https://www.firebase.com/blog/2015-10-07-how-to-keep-your-data-consistent.html
    
        var fanoutObject = [String:AnyObject]()
        fanoutObject[userDataPath] = userData
        fanoutObject[usernameToUidDataPath] = uid
    
        let ref = Firebase(url: "https://YOUR-FIREBASE-URL.firebaseio.com/images")
        ref.updateChildValues(fanoutObject, withCompletionBlock: {
            err, snap in
            if err == nil {
                //call success call back if there were no errors
                successBlock()
            } else {
                //handle error here
                errorBlock()
            }
        })
    }
    

    In addition to this you possibly want to store for each user a list of his followers and a separate list of users he follows. This can be done just by storing user ids at a path like followers/jack_uid, for example it can look like this:

    {
       "firebase_generated_userid_4": true,
       "firebase_generated_userid_14": true
    }
    

    This is the way we store sets of values in our app. It very convenient, because it is really user to update it and check if some value is there.

    In order to count the number of followers, we put this counter into user's data directly. This makes reading the counter very efficient. However, updating this counter requires using transactional writes and the idea is almost exactly the same as in my answer here: Upvote/Downvote system within Swift via Firebase

    Read/write permissions

    A part of your question is how to handle permissions to data you store. The good news is that Firebase is exceptionally good here. If you go to your Firebase dashboard there is a tab named Security&Rules and this is the place where you control permissions to your data.

    What's great about Firebase rules is that they are declarative, which makes them very easy to use and maintain. However, writing rules in pure JSON is not the best idea since it's quite hard to control them when you want to combine some atomic rules into a bigger rule or your app simple grows and there are more and more different data you store in your Firebase database. Fortunately, Firebase team wrote Bolt, which is a language in which you can write all rules you need very easily.

    First of all I recommend to read Firebase docs about Security, especially how does permission to a node influences permission for its children. Then, you can take a look at Bolt here:

    https://www.firebase.com/docs/security/bolt/guide.html https://www.firebase.com/blog/2015-11-09-introducing-the-bolt-compiler.html https://github.com/firebase/bolt/blob/master/docs/guide.md

    For example, we use rules for managing users data similar to this:

    //global helpers
    isCurrentUser(userId) {
        auth != null && auth.uid == userId;
    }
    
    isLogged() {
        auth != null;
    }
    
    //custom types, you can extend them
    //if you want to
    type UserId extends String;
    type Username extends String;
    type AvatarUrl extends String;
    type Email extends String;
    
    type User {
        avatar_url: AvatarUrl,
        bio: String,
        email: Email,
        followers: Number,
        following: Number,
        name: String,
        username: Username,
    }
    
    //user data rules
    path /users/{$userId} is User {
        write() { isCurrentUser($userId) }
        read() { isLogged() }
    }
    
    //user's followers rules
    //rules for users a particular
    //user follows are similar
    path /followers/{$userId} {
        read() { isLogged() }
    }
    
    path /followers/{$userId}/{$followerId} is Boolean {
        create() { isCurrentUser($followerId) && this == true }
        delete() { isCurrentUser($followerId) }
    }
    
    //username to uid rules
    path /username_to_uid {
        read() { true }
    }
    
    path /username_to_uid/{$username} is UserId {
        create() { isCurrentUser(this) }
    }
    

    The bottom line is that you write rules you want using Bolt, then you compile them into JSON using Bolt compiler and then you deploy them into your Firebase, using command line tools or by pasting them into dashboard, but command line is way more efficient. A nice additional feature is that you can test your rules by using tools in Simulator tab in your dashboard.

    Summary

    For me Firebase is a great tool for implementing a system you want. However, I recommend to start with simple features and learn how to use Firebase in the first place. Implementing social app with functionality like for example Instagram is quite a big challenge, especially if you want to do it right :) It's very tempting to put all functionality there very quickly and Firebase makes it relatively easy to do, but I recommend to be patient here.

    In addition, take your time and invest in writing tools. For example, we have two separated Firebase databases, one for production and second for testing, which is really important if you want to write unit and UI tests efficiently.

    Also, I recommend building permission rules from the beginning. Adding them later may be tempting, but also quite overwhelming.

    Last but not least, follow Firebase blog. They post regularly and you can be up to date with their latest features and updates - this is how I learnt how to use concurrent writes using fanout technique.

    这篇关于Firebase数据库帮助 - Swift的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆