asynchronous加载 – UITableView和Firebase

我正在从Firebase加载列表数据并填充UITableView的项目。 虽然我看到从我的firebase实例调用的快照,但它们不会填充表,而本地同步的NSMutableArray会显示内容。 如何让我的UITableView等待Firebase数据到达那里?

代码如下:

- (void)viewDidLoad { [super viewDidLoad]; handles = [[NSMutableArray alloc] initWithObjects:@"Item No. 1", @"Item No. 2", @"Item No. 3", @"Item No. 4", @"Item No. 5", @"Item No. 6", nil]; [self loadDataFromFirebase]; NSLog(@"%lu", (unsigned long)[handles count]); self.sampleTableView.delegate = self; self.sampleTableView.dataSource = self; } -(void)loadDataFromFirebase { Firebase* listRef = [[Firebase alloc] initWithUrl:@"https://wheresthatfoodtruck.firebaseIO.com/foodtrucks"]; [listRef observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) { NSLog(@"%@", snapshot.value); [handles addObject:snapshot.value]; }]; } 

句柄打印出商品编号,但是如果我移除了这个testing数据,[Handles count]就会变成零,UITableView的加载速度会更快,然后从Firebase获取数据。 非常感谢 – 我真的很喜欢Firebase,它是一个很棒的平台,我希望能够通过这个问题。

借助Firebase,您必须记住,所有代码(特别是实时更新的块)都是asynchronous的。 例如,在原始问题的评论以及解决scheme的答案中,代码如下所示:

 [self loadDataFromFirebase]; [self.sampleTableView reloadData]; 

…不能从上到下阅读; 在asynchronous块中正在填充的数据(或正在更新的视图)与正在调用的reloadData之间将存在争用条件 ; 也许单元格连接是不稳定的,或者GCD正在优化一个事物,等等。

Firebase要记住的第二件事情是,对于像child_added这样的事件,可能从来没有任何“完整”的概念 – 数据不断变化和更新是完全可能的; 再次,当一个人期望reloadData被调用? 马上? 第一个孩子之后? 最后一个孩子? 这样做的含义是,如果添加新数据,即使解决方法也会产生您可能不期望的行为(即,数据不会显示出来,因为reloadData将永远不会再被调用。 )

您可以采取的一种方法是在数据更改时直接更新您的视图; 所以,你的块会看起来像:

 [listRef observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) { NSLog(@"%@", snapshot.value); [handles addObject:snapshot.value]; [self.sampleTableView reloadData]; }]; 

另一种方法可能是使用Firebase专门更新内部模型,并使用常规的Objective-C方法(KVO,Notifications,MVC等)分离数据并查看问题,以便在对模型的直接更改之外重新提交视图。

弄清楚了。 而不是试图查询viewDidLoad中的数据库,在这种情况下,视图已经成为一个框架,我把查询移动到nib加载时,但在框架变得可见之前。 代码如下:

 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { //link the CloudViewController with its View NSBundle *appBundle = [NSBundle mainBundle]; self = [super initWithNibName:@"FoodTruckViewController" bundle:appBundle]; if (self) { self.sampleTableView.delegate = self; self.sampleTableView.dataSource = self; [self loadDataFromFirebase]; [self.sampleTableView reloadData]; } return self; } - (void)viewDidLoad { [super viewDidLoad]; [self.sampleTableView reloadData]; } -(void)loadDataFromFirebase { handles = [[NSMutableArray alloc] init]; Firebase* listRef = [[Firebase alloc] initWithUrl:@"https://wheresthatfoodtruck.firebaseIO.com/foodtrucks"]; [listRef observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) { NSLog(@"%@", snapshot.value); [handles addObject:snapshot.value]; }]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [handles count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } [cell.textLabel setText:[handles objectAtIndex:indexPath.row]]; return cell; } #pragma mark - Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Navigation logic may go here. Create and push another view controller. /* <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil]; // ... // Pass the selected object to the new view controller. [self.navigationController pushViewController:detailViewController animated:YES]; */ } @end 

此版本的代码在表格可见之前填充表格,但不会实时更新表格。 我认为下一步将是在viewDidLoad方法中调用FireCase的ChildChanged函数窗体来更新Firebase上的所有更改。