【问题标题】:Swift Firebase loading records with long delaySwift Firebase 加载记录延迟很长
【发布时间】:2016-12-11 02:18:55
【问题描述】:

我正在使用 Firebase 构建一个 Swift 应用程序,而且我对这两个应用程序都很陌生,所以请保持温和。目前,当我打开应用程序时,它会再次同步整个数据库并导致用户盯着空的 tableview 时出现 2 或 3 秒的延迟。如何加快速度?

有什么想法吗?

我的代码:

我的 loadContacts 函数

func loadContact(snap : FIRDataSnapshot) -> Contact {
let key = snap.key
let contact = (snap.value) as? NSDictionary

let c1 = Contact(
    id: (contact?["id"] as? String)!,
    firebasekey: key,
    first_name: (contact?["First Name"] as? String)!,
    middle_name: (contact?["Middle Name"] as? String)!,
    last_name: (contact?["Last Name"] as? String)!,
    suffix: (contact?["Suffix"] as? String)!,
    company: (contact?["Company"] as? String)!,
    phone_labe1: (contact?["Phone Label 1"] as? String)!,
    phone1: (contact?["Phone 1"] as? String)!,
    phone_label2: (contact?["Phone Label 2"] as? String)!,
    phone2: (contact?["Phone 2"] as? String)!,
    email_label1: (contact?["Email Label 1"] as? String)!,
    email1: (contact?["Email 1"] as? String)!,
    email_label2: (contact?["Email Label 2"] as? String)!,
    email2: (contact?["Email 2"] as?  String)!,
    social: (contact?["Social Security Number"] as? String)!,
    dob: (contact?["Date of Birth"] as? String)!,
    street: (contact?["Street"] as? String)!,
    city: (contact?["City"] as? String)!,
    zip: (contact?["ZIP and Postal Code"] as? String)!,
    state: (contact?["State and Province"] as? String)!,
    reg_number: (contact?["Reg Num"] as? String)!,
    stable_reg_number: (contact?["Stable Reg Num"] as? String)!,
    emergency_contact: (contact?["Emergency Contact"] as? String)!,
    emergency_phone: (contact?["Emergency Phone"] as? String)!,
    drivers_license: (contact?["Driver's License Num"] as? String)!,
    insurance_carrier: (contact?["Insurance Carrier"] as? String)!,
    details: (contact?["Details"] as? String)!,
    insurance_exp: (contact?["Insurance Expiration Date"] as? String)!,
    insurance_group: (contact?["Insurance Group Num"] as? String)!,
    insurance_member: (contact?["Insurnace Member Num"] as? String)!, // spelled wrong in database
    job_title: (contact?["Job Title"] as? String)!,
    date_modified: (contact?["Modified"] as? String)!,
    keywords: [],
    notes: []
)

return c1;
}

在我的联系人表格视图中

import UIKit
import Firebase

class ContactTableViewController: UITableViewController, UISearchBarDelegate, UISearchDisplayDelegate {
// MARK: Properties
var contactSearchResults : [Contact] = []

// FIRDatabase.database().persistenceEnabled = true
let contactRef = FIRDatabase.database().reference().child("contacts")

override func viewDidLoad() {

    contactRef.queryOrdered(byChild: "Last Name").observe(.childAdded) { (snap: FIRDataSnapshot) in
        contacts.append(loadContact(snap: snap))
        self.tableView.reloadData()
    }

    contactRef.queryOrdered(byChild: "Last Name").observe(.childChanged) { (snap: FIRDataSnapshot) in
        // this code here is wrong, but it doesn't matter for demonstration purposes
        contacts.append(loadContact(snap: snap))
        self.tableView.reloadData()
    }

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

我的数据库结构类似于

联系人(我的问题区域)中有大约 4000 条记录,每个记录有 33 个单独的子值。

【问题讨论】:

  • Firebase 是一个实时数据库,它应该消除在本地存储数据的需要 - 这将根据您的用例而有所不同。话虽如此,如果您从 Firebase 加载 tableView 有 2-3 秒的延迟,那么您还有其他问题,因为它应该感觉几乎是立即的;在几分之一秒内加载数千名用户。另一个问题是您提到“它再次同步整个数据库”,这有点奇怪,因为它应该只从 Firebase 检索适用于您向用户显示的(例如)tableView 的数据。
  • @Jay 感谢您的回复!我几乎可以立即加载,您对导致延迟的原因有什么建议吗?
  • @NickWinner 我们需要查看更多代码和数据库结构才能回答这个问题。
  • 您的延迟可能与硬件/互联网相关,也可能是编码错误。很难说。您可以随时通过speedof.me 测试您的互联网响应。但即使连接速度为 10Mbps,Firebase 服务器也非常快,您应该能够在几分之一秒内加载数千字节的数据。作为一个比较点,通过该测试,我运行 200Mbps 下降和 18Mbp​​s 上升,24ms 延迟。首先检查一下,如果不是,请检查您的代码。
  • @JordiBruin 好的,我已经编辑了我的帖子以包含相关代码(我认为)。我已经尝试过您的建议,但我无法摆脱这种滞后。

标签: ios swift firebase firebase-realtime-database offline


【解决方案1】:

问题中的代码存在许多会影响性能的问题。

1) 最初为每个孩子触发的孩子添加事件,然后为之后添加的任何孩子触发。如果您有 1000 个联系人,这意味着在启动时,您将刷新表格视图 1000 次。您最好通过 .value 加载所有联系人并对其进行迭代,添加到数组中,然后在完成后刷新 tableView

2) 与 #1 一样,如果您只想按姓氏对它们进行排序,请按 .value 观察节点,遍历快照以填充数组,然后排序,然后重新加载 tableView。这将明显更快。

3) childChanged 事件:没有理由按姓氏查询,因为当孩子发生变化时,它只会通知您该孩子,如果需要,您可以在代码中排序

4) 与观察事件相比,Firebase 查询非常“繁重”。在这种情况下,您实际上并没有特别查询任何内容,因此应该将其消除。只需使用观察事件来加载节点的数据价值,并在查找该数据的子集时使用查询。

*请注意,这在很大程度上取决于您拥有多少联系人。对于几千个这些建议工作正常。

因此,有一种非常酷的设计模式可以让初始数据集的填充变得非常干净。我认为其中一位 Firebaser 将其作为示例应用程序的一部分编写。

我们首先定义一个名为 initialLoad 的类级别变量并将其设置为 true。然后我们使用 childAdded 观察来加载所有联系人并填充我们的 tableView 数据源数组。

var initialLoad = true

contactsRef.observeEventType(.ChildAdded, withBlock: { snapshot in
     self.handleChildAdded(withSnap: snapshot)
})

以及处理 childAdded 事件的函数,最初一次加载每个孩子,并观察之后添加的孩子。

func handleChildAdded(withSnap: snapshot: FDataSnapshot! ) {
    let myContact = Contact()
    myContact.initWithSnap(snapshot)
    myDataSourceArray.append(myContact)

    //upon first load, don't reload the tableView until all children are loaded
    if ( self.initialLoad == false ) { 
            self.contactsTableView.reloadData()
    }    
}

现在是棘手的部分

//this .Value event will fire AFTER the child added events to reload the tableView 
//  the first time and to set subsequent childAdded events to load after each child is
//    added in the future
contactsRef.observeSingleEventOfType(.Value, withBlock: { snapshot in      
     print("inital data loaded so reload tableView!")
     self.itemsTableView.reloadData()
     self.initialLoad = false
})

10k 英尺视图:

这里的关键是 .value 事件在 .childAdded 事件之后触发,因此我们利用它在所有子添加事件完成后将 initialLoad 变量设置为 false。

上面的代码是 Swift 2/3,Firebase 2,但它为您提供了如何进行初始加载的概念。

【讨论】:

  • 感谢最后一个例子!
  • 谢谢!这使我从将近 7 秒的延迟减少到大约 3 秒。
  • 第一次为我加载初始数据需要花费大量时间,为什么会这样?
  • @PatelJigar 没有看到你的代码很难说。也许您可以发布有关该问题的问题?请务必在问题中包含代码和 Firebase 结构的 sn-p。
猜你喜欢
  • 2017-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-05
  • 1970-01-01
  • 2015-12-06
  • 1970-01-01
  • 2013-11-08
相关资源
最近更新 更多