获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

在 Apple 平台上使用数据列表

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

获取 FIRDatabaseReference

要从数据库读取或写入数据,您需要一个FIRDatabaseReference实例:

迅速

注意:此 Firebase 产品不适用于 App Clip 目标。
var ref: DatabaseReference!

ref = Database.database().reference()

Objective-C

注意:此 Firebase 产品不适用于 App Clip 目标。
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];

阅读和写作清单

附加到数据列表

使用childByAutoId方法将数据附加到多用户应用程序中的列表。每次将新子项添加到指定的 Firebase 引用时, childByAutoId方法都会生成一个唯一键。通过为列表中的每个新元素使用这些自动生成的键,多个客户端可以同时将子元素添加到同一位置,而不会发生写入冲突。 childByAutoId生成的唯一键是基于时间戳的,因此列表项会自动按时间顺序排列。

您可以使用对childByAutoId方法返回的新数据的引用来获取孩子的自动生成键的值或为孩子设置数据。在childByAutoId引用上调用getKey会返回自动生成的密钥。

您可以使用这些自动生成的键来简化数据结构的扁平化。有关详细信息,请参阅数据扇出示例

监听子事件

子事件被触发以响应某个操作对节点的子节点发生的特定操作,例如通过childByAutoId方法添加的新子节点或通过updateChildValues方法更新的子节点。

事件类型典型用法
FIRDataEventTypeChildAdded检索项目列表或监听项目列表的添加。此事件为每个现有的孩子触发一次,然后在每次将新的孩子添加到指定路径时再次触发。侦听器被传递一个包含新孩子数据的快照。
FIRDataEventTypeChildChanged监听列表中项目的更改。每当修改子节点时都会触发此事件。这包括对子节点后代的任何修改。传递给事件侦听器的快照包含子节点的更新数据。
FIRDataEventTypeChildRemoved侦听从列表中删除的项目。此事件在删除直接子项时触发。传递给回调块的快照包含已删除子项的数据。
FIRDataEventTypeChildMoved监听有序列表中项目顺序的变化。每当更新导致子项重新排序时,都会触发此事件。它用于由queryOrderedByChildqueryOrderedByValue排序的数据。

这些中的每一个都可用于监听数据库中特定节点的更改。例如,社交博客应用程序可能会同时使用这些方法来监控帖子评论中的活动,如下所示:

迅速

注意:此 Firebase 产品不适用于 App Clip 目标。
// Listen for new comments in the Firebase database
commentsRef.observe(.childAdded, with: { (snapshot) -> Void in
  self.comments.append(snapshot)
  self.tableView.insertRows(
    at: [IndexPath(row: self.comments.count - 1, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})
// Listen for deleted comments in the Firebase database
commentsRef.observe(.childRemoved, with: { (snapshot) -> Void in
  let index = self.indexOfMessage(snapshot)
  self.comments.remove(at: index)
  self.tableView.deleteRows(
    at: [IndexPath(row: index, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})

Objective-C

注意:此 Firebase 产品不适用于 App Clip 目标。
// Listen for new comments in the Firebase database
[_commentsRef
              observeEventType:FIRDataEventTypeChildAdded
              withBlock:^(FIRDataSnapshot *snapshot) {
                [self.comments addObject:snapshot];
                [self.tableView insertRowsAtIndexPaths:@[
                  [NSIndexPath indexPathForRow:self.comments.count - 1 inSection:kSectionComments]
                ]
                                      withRowAnimation:UITableViewRowAnimationAutomatic];
              }];
// Listen for deleted comments in the Firebase database
[_commentsRef
 observeEventType:FIRDataEventTypeChildRemoved
 withBlock:^(FIRDataSnapshot *snapshot) {
   int index = [self indexOfMessage:snapshot];
   [self.comments removeObjectAtIndex:index];
   [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:kSectionComments]]
                         withRowAnimation:UITableViewRowAnimationAutomatic];
 }];

监听价值事件

虽然监听子事件是读取数据列表的推荐方法,但在某些情况下监听列表引用上的值事件很有用。

FIRDataEventTypeValue观察者附加到数据列表将返回整个数据列表作为单个 DataSnapshot,然后您可以循环访问单个子节点。

即使查询只有一个匹配项,快照仍然是一个列表;它只包含一个项目。要访问该项目,您需要遍历结果:

迅速

注意:此 Firebase 产品不适用于 App Clip 目标。
_commentsRef.observe(.value) { snapshot in
  for child in snapshot.children {
    ...
  }
}

Objective-C

注意:此 Firebase 产品不适用于 App Clip 目标。
[_commentsRef
              observeEventType:FIRDataEventTypeValue
              withBlock:^(FIRDataSnapshot *snapshot) {
                // Loop over children
                NSEnumerator *children = [snapshot children];
                FIRDataSnapshot *child;
                while (child = [children nextObject]) {
                  // ...
                }
              }];

当您想在单个操作中获取列表的所有子项而不是侦听附加的子项添加事件时,此模式很有用。

排序和过滤数据

您可以使用实时数据库FIRDatabaseQuery类来检索按键、值或子值排序的数据。您还可以将排序结果筛选为特定数量的结果或键或值范围。

排序数据

要检索已排序的数据,请首先指定一种 order-by 方法来确定结果的排序方式:

方法用法
queryOrderedByKey按子键排序结果。
queryOrderedByValue按子值排序结果。
queryOrderedByChild按指定子键或嵌套子路径的值对结果进行排序。

您一次只能使用一种排序方法。在同一个查询中多次调用 order-by 方法会引发错误。

以下示例演示了如何检索按星数排序的用户热门帖子列表:

迅速

注意:此 Firebase 产品不适用于 App Clip 目标。
// My top posts by number of stars
let myTopPostsQuery = ref.child("user-posts").child(getUid()).queryOrdered(byChild: "starCount")

Objective-C

注意:此 Firebase 产品不适用于 App Clip 目标。
// My top posts by number of stars
FIRDatabaseQuery *myTopPostsQuery = [[[self.ref child:@"user-posts"]
                                      child:[super getUid]]
                                     queryOrderedByChild:@"starCount"];

此查询根据用户 ID 从数据库中的路径检索用户的帖子,按每个帖子收到的星数排序。这种使用 ID 作为索引键的技术称为数据扇出,您可以在Structure Your Database中了解更多信息。

queryOrderedByChild方法的调用指定了结果排序依据的子键。在此示例中,帖子按每个帖子中"starCount"子项的值排序。查询也可以按嵌套子级排序,以防您的数据如下所示:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

在这种情况下,我们可以通过在queryOrderedByChild调用中指定嵌套子级的相对路径,按嵌套在metrics键下的值对列表元素进行排序。

迅速

注意:此 Firebase 产品不适用于 App Clip 目标。
 
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")

Objective-C

注意:此 Firebase 产品不适用于 App Clip 目标。
 
FIRDatabaseQuery *postsByMostPopular = [[ref child:@"posts"] queryOrderedByChild:@"metrics/views"];

有关其他数据类型如何排序的详细信息,请参阅查询数据的排序方式

过滤数据

要过滤数据,您可以在构造查询时将任何限制或范围方法与 order-by 方法结合使用。

方法用法
queryLimitedToFirst设置从有序结果列表的开头返回的最大项目数。
queryLimitedToLast设置从有序结果列表末尾返回的最大项目数。
queryStartingAtValue根据选择的 order-by 方法,返回大于或等于指定键或值的项目。
queryStartingAfterValue根据选择的 order-by 方法,返回大于指定键或值的项目。
queryEndingAtValue根据选择的 order-by 方法,返回小于或等于指定键或值的项目。
queryEndingBeforeValue根据选择的 order-by 方法,返回小于指定键或值的项目。
queryEqualToValue根据选择的 order-by 方法,返回等于指定键或值的项目。

与 order-by 方法不同,您可以组合多个限制或范围函数。例如,您可以组合queryStartingAtValuequeryEndingAtValue方法来将结果限制在指定的值范围内。

限制结果数量

您可以使用queryLimitedToFirstqueryLimitedToLast方法来设置要为给定回调同步的最大子级数。例如,如果您使用queryLimitedToFirst将限制设置为 100,那么您最初最多只能收到 100 个FIRDataEventTypeChildAdded回调。如果您的 Firebase 数据库中存储的项目少于 100 个,则会为每个项目触发一个FIRDataEventTypeChildAdded回调。

随着项目的变化,您会收到进入查询的项目的FIRDataEventTypeChildAdded回调和退出查询的项目的FIRDataEventTypeChildRemoved回调,因此总数保持在 100。

以下示例演示了示例博客应用程序如何检索所有用户最近发布的 100 篇文章的列表:

迅速

注意:此 Firebase 产品不适用于 App Clip 目标。
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
let recentPostsQuery = (ref?.child("posts").queryLimited(toFirst: 100))!

Objective-C

注意:此 Firebase 产品不适用于 App Clip 目标。
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
FIRDatabaseQuery *recentPostsQuery = [[self.ref child:@"posts"] queryLimitedToFirst:100];

按键或值过滤

您可以使用queryStartingAtValuequeryStartingAfterValuequeryEndingAtValuequeryEndingBeforeValuequeryEqualToValue来选择查询的任意起点、终点和等价点。这对于对数据进行分页或查找具有特定值的子项非常有用。

查询数据如何排序

本节说明如何通过FIRDatabaseQuery类中的每个 order-by 方法对数据进行排序。

queryOrderedByKey

使用queryOrderedByKey对数据进行排序时,数据按 key 升序返回。

  1. 具有可以被解析为 32 位整数的键的子项排在最前面,按升序排序。
  2. 以字符串值作为键的子项紧随其后,按字典顺序升序排序。

queryOrderedByValue

使用queryOrderedByValue时,子项按其值排序。排序标准与queryOrderedByChild中的相同,只是使用节点的值而不是指定子键的值。

queryOrderedByChild

使用queryOrderedByChild时,包含指定子键的数据按如下顺序排列:

  1. 具有指定子键的nil值的子项首先出现。
  2. 接下来是指定子键的值为false的子项。如果多个孩子的值为false ,则它们按字典顺序键排序。
  3. 接下来是指定子键的值为true的子项。如果多个孩子的值为true ,则它们按字典顺序键排序。
  4. 接下来是具有数值的子项,按升序排序。如果指定子节点的多个子节点的数值相同,则按key排序。
  5. 字符串在数字之后,并按字典顺序升序排序。如果指定子节点的多个子节点具有相同的值,则它们按字典顺序键排序。
  6. 对象排在最后,并按关键字按字典顺序升序排序。

分离监听器

当您离开ViewController时,观察者不会自动停止同步数据。如果没有正确删除观察者,它会继续将数据同步到本地内存,并将保留在事件处理程序闭包中捕获的任何对象,这可能导致内存泄漏。当不再需要观察者时,通过将关联的FIRDatabaseHandle传递给removeObserverWithHandle方法来移除它。

将回调块添加到引用时,将返回FIRDatabaseHandle 。这些句柄可用于删除回调块。

如果已将多个侦听器添加到数据库引用,则在引发事件时调用每个侦听器。为了停止在该位置同步数据,您必须通过调用removeAllObservers方法删除该位置的所有观察者。

在侦听器上调用removeObserverWithHandleremoveAllObservers不会自动删除在其子节点上注册的侦听器;您还必须跟踪这些引用或句柄以删除它们。

下一步