Swift Firebase的加载记录延迟很长 [英] Swift Firebase loading records with long delay

查看:152
本文介绍了Swift Firebase的加载记录延迟很长的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



有什么想法?



我的代码:



我的loadContacts函数

$ p $ func loadContact(snap:FIRDataSnapshot) - >联系{
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 (字符串)!,
后缀:(联系人?[后缀]为字符串)!,
公司:(contact?[公司]为?字符串)!,
phone_labe1 :(联系人?[电话标签1]为?字符串)!,
phone1:(联系人?[电话1]为?字符串)!,
phone_label2:(contact?[Phone标签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?[Email2] as String)!,
social:(contact?[Social Security Number] as String)!,
dob:(contact?[出生日期] as?String)!,
street:(con机智?[街道]?字符串)!,
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? 稳定的注册号码as?字符串)!,
emergency_contact:(contact?[Emergency Contact] as?String)!,
emergency_phone:(联系?[Emergency Phone] as?字符串)!,
drivers_license:(contact?[驾驶执照号码as?字符串)!,
insurance_carrier :(联系人?[Insurance Carrier]字符串)!,
详细信息:(联系人?[Details] as?String)!,
insurance_exp:(contact?[Insurance Expiration Date] as String)!,
insurance_group :(联系人?[保险集团Num] as?String)!,
insurance_member:(contact?[Insurnace Member Num] as String)!, //在数据库拼写错误
job_title:(contact?[ Job Title] as?String)!,
date_modified:(contact?[Modi fied]为?字符串)!,
关键字:[],
备注:[]


return c1;
}

而且在我的联系人表格视图中

  import UIKit 
import Firebase

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

// FIRDatabase.database()。persistenceEnabled = true
let contactRef = FIRDatabase.database()联系人)

覆盖func viewDidLoad(){
$ b $ contactRef.queryOrdered(byChild:Last Name).atour(.childAdded){(snap:FIRDataSnapshot)in
contacts.append(loadContact(snap:snap))
self.tableView.reloadData()
}

contactRef.queryOrdered(byChild:Last Name)。在
中观察(.childChanged){(snap:FIRDataSnapshot)//这里的代码是错误的,但是对于演示来说并不重要
contacts.append(loadContact(snap:snap))
self.tableView .reloadData()
}

//取消注释以下行以保留演示文稿之间的选择
// self.clearsSelectionOnViewWillAppear = false

//取消注释以下行显示此视图控制器的导航栏中的编辑按钮。
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

我的数据库结构像



< img src =https://i.stack.imgur.com/wLsK8.pngalt =在这里输入图片描述>



通讯录(我的问题领域)有大约4000条记录,每条记录有33个独立的子值。 解决方案

在这个问题,将影响性能。



1)小孩添加事件最初触发每个孩子,然后为任何后来添加的孩子。如果您有1000个联系人,这意味着启动时,您正在刷新1000次的表视图。你可以通过.value加载所有的联系人,迭代它们,添加到一个数组,然后在完成时刷新tableView,这样会更好。


2) #1,如果你只是想按姓氏排序,通过.value观察节点,遍历快照填充数组,然后排序,然后重新加载tableView。 3)childChanged事件:当孩子改变时,没有理由用姓氏来查询,它只会通知你那个孩子,然后再次,您可以根据需要在代码中进行排序。

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

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

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



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

$ $ $ $ $ $ $ $ $ $ $ $ $ var $ initial $ true

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

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

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

//在第一次加载时,不要重载tableView,直到所有的孩子被加载
if(self.initialLoad == false){
self。 contactsTableView.reloadData()
}
}

p>

  //这个.Value事件会触发AFT ER子项添加事件重新加载tableView 
//第一次,并设置后续childAdded事件加载后,每个孩子
/ /未来添加
contactsRef.observeSingleEventOfType(.Value ,withBlock:{快照在
print(inital data loaded so reload tableView!)
self.itemsTableView.reloadData()
self.initialLoad = false
})

10k尺寸视图:

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

上面的代码是Swift 2/3,Firebase 2,但它给你如何做你的初始负载的概念。


I'm building a Swift app using Firebase, and I'm new to both so be gentle. Currently, when I open the app, it syncs the entire database again and causes a 2 or 3 second lag where the user stares at an empty tableview. How can I speed this up?

Any thoughts?

My code:

My loadContacts function

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;
}

And in my contact table view

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

My database has structured like

Contacts (my problem area) has about 4000 records in it with 33 individual children values each.

解决方案

There are number of issues with the code in the question that will affect performance.

1) The child added event fires for every child initially and then for any children added afterwards. If you have 1000 contacts, that means on startup, you are refreshing the table view 1000 times. You would be better off loading all of the contacts by .value and iterating over them, adding to an array, and then refreshing the tableView when done

2) Going along with #1, if you just want to order them by last name, observe the node by .value, iterate over the snapshot to populate the array and then sort, then reload the tableView. That will be significantly faster.

3) The childChanged event: there's no reason to query by last name as when a child changes, it notifies you of just that child and again, you can sort in code if needed

4) Firebase queries are very 'heavy' by comparison to observe events. In this case you really are not querying for any in particular so that should be eliminated. Just use observe events to load a node's worth of data and use a query when you are looking for a subset of that data.

*note that a lot of this depends on how many contacts you have. For a few thousand these suggestions work fine.

So there's a really cool design pattern that makes populating an initial dataset really clean. I think one of the Firebasers wrote it as part of an example app.

We start with defining an class level variable called initialLoad and set it to true. Then we use a childAdded observe to load in all the contacts and populate our tableView dataSource array.

var initialLoad = true

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

and the function to handle childAdded events and will initially load each child one at a time, and watch for children added after that.

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

Now the tricky bit

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

The the 10k foot view:

The key here is that .value events fire AFTER .childAdded events so we are leveraging that to set the initialLoad variable to false AFTER all of the child added events complete.

The above code is Swift 2/3, Firebase 2 but it gives you the concept of how to do your initial load.

这篇关于Swift Firebase的加载记录延迟很长的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆