Swift Firebase 加载记录延迟很长

Posted

技术标签:

【中文标题】Swift Firebase 加载记录延迟很长【英文标题】:Swift Firebase loading records with long delay 【发布时间】: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 好的,我已经编辑了我的帖子以包含相关代码(我认为)。我已经尝试过您的建议,但我无法摆脱这种滞后。 【参考方案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。

以上是关于Swift Firebase 加载记录延迟很长的主要内容,如果未能解决你的问题,请参考以下文章

在 TableViewCell Swift 中从 Firebase 加载图像

从 Firebase 中基本读取并使用结果加载 tableview (Swift)

从firebase加载图像并缓存swift3

Swift 3:tableView 复制从 Firebase 加载的图像

扩展中的延迟加载属性(Swift)

Firebase 和 Alamofire Url TableViewCell 图像加载问题 Swift 4