我正在使用Firebase构建一个Swift应用程序,而且我是两个新手都很温柔。目前,当我打开应用程序时,它会再次同步整个数据库,并导致2或3秒滞后,用户盯着空的tableview。我怎样才能加快速度呢?
有什么想法吗?
我的代码:
我的loadContacts函数
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()
}
在我的联系表视图中
public class CustomInterceptor implements Interceptor {
private static final Charset UTF8 = Charset.forName("UTF-8");
@Override
public Response intercept(Chain chain) throws IOException {
final Request request = chain.request();
final String urlStr = request.url().toString();
final Request.Builder builder = request.newBuilder();
if (request.body() != null && request.body() instanceof FormBody) {
.
.
.
.
.
final RequestBody newBody = RequestBody.create(mediaType, content);
final Request newRequest = builder.url(urlStr)
.header("User-Agent", ApiUtils.getUserAgent())
.header("Content-Type", oldBody.contentType().toString())
.header("Content-Length", String.valueOf(content.length()))
.method(request.method(), newBody)
.build();
//
final Response response = chain.proceed(newRequest);
final ResponseBody responseBody = response.body();
final Headers headers = response.headers();
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE); // Buffer the entire body.
Buffer buffer = source.buffer();
Charset charset = UTF8;
MediaType contentType = responseBody.contentType();
String realResult;
try {
if (contentType != null) {
charset = contentType.charset(UTF8);
}
final String result = buffer.clone().readString(charset);//garbled
.
.
.
.
.
} catch (Exception e) {
Logger.v(e.getMessage());
return response;
}
return response.newBuilder()
.body(ResponseBody.create(contentType != null ? contentType : MediaType.parse(oldBody.contentType().toString()),
realResult.getBytes()))
.build();
}
}
}
我的数据库结构类似
联系人(我的问题区域)中有大约4000条记录,每条记录有33个单独的子项值。
答案 0 :(得分: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)
})
以及处理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事件触发AFTER .childAdded事件,因此我们利用它来将所有子添加事件完成后的initialLoad变量设置为false。
以上代码是Swift 2/3,Firebase 2,但它为您提供了如何进行初始加载的概念。