swift - 在Firebase中构建用户数据库模型

标签 swift xcode firebase firebase-realtime-database backend

所以我已经完成了所有的实际应用程序。我只需要设置后端。我认为Firebase是最好的解决方案,因为解析不再是一件事了。我想要的是:
有配置文件的用户-这些配置文件可以由添加的朋友查看,但只能由实际的配置文件所有者编辑(写入)。
所以我通读了Firebase的文档,仍然不知道该怎么做。他们只有一个Swift应用程序示例,没有做任何类似的事情,一个Obj C twitter示例,甚至不会构建。他们所有的文档仍然有Swift的println,这让我觉得它不经常更新。
有人有这方面的好例子/教程吗?我一直在努力寻找东西,但没有什么东西能像我想要的那样相似。我更关注的是如何为每个用户设置数据库并访问它,而不是实际使用Swift中的Firebase。

最佳答案

正如我在对你的问题的评论中所写的,这个答案是基于我们在一个真正的社交应用程序中使用Swift+Firebase所做的。
数据结构
假设要为单个用户存储以下信息:
电子邮件
用户名
名称
关注者-关注特定用户的人数
following—特定用户关注的人数
avatar_url-他们的avatar的url
生物-一些附加文本
由于在Firebase中,所有内容都存储一个JSON对象,因此您可以将上述结构存储在路径类似于users/$userId的节点下,其中$userId是Firebase用户UID,如果您使用简单的电子邮件/密码Firebase授权,则为每个注册用户创建。
Firebase电子邮件/密码授权在其文档中有描述:
Impether
https://www.firebase.com/docs/ios/guide/user-auth.html
注意,Obj-C和Swift代码片段都有。我发现Firebase文档非常棒,因为它在我构建应用程序时帮了我很多忙。
为了回答这个问题,假设我们有用户名为jack的用户,而Firebase用户UID等于jack_uid(实际上这是Firebase生成的字符串)。
然后,此用户的示例数据将存储在路径users/jack_uid下,可以如下所示:

{
  "email" : "jack@example.com",
  "username" : "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下,如下所示:
{ 
   "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) {

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

除此之外,您可能还想为每个用户存储一个他的追随者列表和一个单独的用户列表。这可以通过将用户id存储在类似于followers/jack_uid的路径来实现,例如,它可以如下所示:
{
   "firebase_generated_userid_4": true,
   "firebase_generated_userid_14": true
}

这是我们在应用程序中存储价值集的方式。它非常方便,因为它是真正的用户更新和检查是否有一些价值。
为了计算关注者的数量,我们将这个计数器直接放入用户的数据中。这使得读取计数器非常有效。但是,更新这个计数器需要使用事务性写入,而且这个想法与我在这里的回答几乎完全相同:https://www.firebase.com/docs/ios/guide/login/password.html
读/写权限
问题的一部分是如何处理对存储的数据的权限。好消息是这里的Firebase非常好。如果您转到Firebase仪表板,会有一个名为Security&Rules的选项卡,您可以在这里控制对数据的权限。
Firebase规则的优点在于它们是声明性的,这使得它们非常易于使用和维护。然而,用纯JSON编写规则并不是最好的主意,因为当你想将一些原子规则组合成一个更大的规则,或者你的应用程序简单地增长,并且你的Firebase数据库中存储了越来越多不同的数据时,很难控制它们。幸运的是,Firebase团队编写了Bolt,这是一种可以很容易地编写所有需要的规则的语言。
首先,我建议阅读有关安全性的Firebase文档,特别是对节点的权限如何影响其子节点的权限。然后,你可以在这里看看博尔特:
Upvote/Downvote system within Swift via Firebase
https://www.firebase.com/docs/security/bolt/guide.html
https://www.firebase.com/blog/2015-11-09-introducing-the-bolt-compiler.html
例如,我们使用类似以下的规则来管理用户数据:
//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) }
}

归根结底,您可以使用Bolt编写想要的规则,然后使用Bolt编译器将它们编译成JSON,然后使用命令行工具或将它们粘贴到仪表板中,将它们部署到Firebase中,但命令行的效率要高得多。另一个很好的特性是,您可以使用仪表板Simulator选项卡中的工具测试规则。
摘要
对我来说,Firebase是实现你想要的系统的一个很好的工具。但是,我建议从简单的特性开始,首先学习如何使用Firebase。使用Instagram之类的功能实现社交应用程序是一个很大的挑战,尤其是如果你想做得好的话:)很容易把所有的功能都放在那里,而Firebase使它相对容易做到,但我建议你在这里要有耐心。
另外,花点时间投资于写作工具。例如,我们有两个独立的Firebase数据库,一个用于生产,另一个用于测试,如果您想高效地编写单元和UI测试,这一点非常重要。
另外,我建议从一开始就建立许可规则。稍后再添加它们可能很诱人,但也相当令人难以抗拒。
最后但并非最不重要的是,关注Firebase博客。他们定期发布,你可以了解他们的最新功能和更新-这是我如何学会使用扇出技术并发写。

关于swift - 在Firebase中构建用户数据库模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37148898/

相关文章:

iphone - 如何阻止willTerminate方法的调用?

iphone - iOS 7,文本字段所有字符大写

android - 如何使用 ionic 3 和 Firebase Cloud Messaging 从通知栏打开特定页面?

swift - 如何在没有字典键的情况下获取值?

ios - Swift:无法在可变对象参数上设置属性值

arrays - 将字符串与字符串数组进行比较并计算 Swift 中的匹配项

swift - 8000 PCM格式的AVAudioEngine如何录音播放?

ios - swift 错误 "Variable used within its own initial value"

ios - 如何知道 UIwebview 是向下滚动还是向上滚动? ( swift )

javascript - Firebase:在测试期间我得到 "undefined is not a function"