Swift Firebase加载记录延迟很长

Nic*_*ner 0 offline ios firebase swift firebase-realtime-database

我正在使用Firebase构建一个Swift应用程序,而且我是两个新手,所以要温柔.目前,当我打开应用程序时,它会再次同步整个数据库,并导致2或3秒滞后,用户盯着空的tableview.我怎样才能加快速度呢?

有什么想法吗?

我的代码:

我的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;
}
Run Code Online (Sandbox Code Playgroud)

并在我的联系表视图中

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()
}
Run Code Online (Sandbox Code Playgroud)

我的数据库结构如下

在此输入图像描述

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

Jay*_*Jay 6

问题中的代码存在许多问题,这些问题会影响性能.

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

2)与#1一起使用,如果您只想按姓氏排序,请按.value观察节点,迭代快照以填充数组然后排序,然后重新加载tableView.这将明显加快.

3)childChanged事件:没有理由按姓氏查询,当孩子改变时,它只通知你那个孩子,如果需要,你可以再次输入代码

4)与观察事件相比,Firebase查询非常"繁重".在这种情况下,你真的不是要特别查询,所以应该被淘汰.只需使用观察事件来加载节点的数据,并在查找该数据的子集时使用查询.

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

因此,有一个非常酷的设计模式,使初始数据集的填充真正干净.我认为其中一个Firebasers将其作为示例应用程序的一部分编写.

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

var initialLoad = true

contactsRef.observeEventType(.ChildAdded, withBlock: { snapshot in
     self.handleChildAdded(withSnap: snapshot)
})
Run Code Online (Sandbox Code Playgroud)

以及处理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()
    }    
}
Run Code Online (Sandbox Code Playgroud)

现在是棘手的一点

//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
})
Run Code Online (Sandbox Code Playgroud)

10k英尺的视图:

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

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