roguequery
roguequery

Reputation: 974

Ordered Arrays with Firebase

As Firebase doesn't guarantee order when reading from a base, we can get unordered output from this async call:

-(void)loadDataFromFirebase
{
    handles = [[NSMutableArray alloc] init];
    Firebase* listRef = [[Firebase alloc] initWithUrl:@"https://mobilefeast.firebaseIO.com/foodtrucks"];
    [listRef observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
        NSLog(@"%@", snapshot.name);
        [handles addObject:snapshot.value];
        [self.handleTableView reloadData];
    }];
}

In the example ordered reading snippet from Firebase, we can order the printing of async data, but this doesn't work so well for NSArrays in iOS, where hole-y, sparse arrays don't exist. What is the right way of populating an array, in order, from Firebase in iOS? I think this can be accomplished with a .json tacked onto the end of a URL for a REST call, but want to try to stick with the native Firebase iOS API. Thanks.

*Edit: * looking for a simple alphabetical sort. It looks like this should happen in Rest, and does with the following URL in REST:

https://mobilefeast.firebaseio.com/foodtrucks/.json

But I can't seem to replicate the same ordering with the iOS Firebase API.

Upvotes: 1

Views: 1357

Answers (1)

Vikrum
Vikrum

Reputation: 1951

In this particular instance, the asynchronous nature of Firebase isn't what's causing the events to be triggered seemingly out of order. Behind the scenes we keep all data as dictionaries—even arrays (See here for the rationale: https://www.firebase.com/docs/managing-lists.html). Since the example code is using the FEventTypeChildAdded event type, callbacks are being triggered lexicographically based on the the keys (in this case, 0, 1, 2, 3, ..., 12, 13, 14...) which is then resulting in the output you're seeing. Take a look here: https://www.firebase.com/docs/ordered-data.html for more details on the various ways ordering plays a role in Firebase events.

Based on your example code and how you expect this data to change and grow, you have a few options:

You could just grab the entire thing all at once using FEventTypeValue in which case we'll pass you a prebuilt NSArray in the correct order. This would look like

[listRef observeEventType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
  NSLog(@"value: %@", snapshot.value);
}];

This would then trigger every time any of the children changed. However, if you're wanting to build up the table incrementally this option might not be well suited.

Another option could be to shift the structure of the data to take advantage of the built-in ordering. So, if there's going to be more data that goes along here in the future, you could shift it so the JSON equivalent looks like:

{
  "alfrescocafe": { "name": "@alfrescocafe", "type": "Truck" },
  "barshagyro": { "name": "@BarshaGyro", "type": "Truck" },
  "bigronsbistro": { "name": "@BigRonsBistro", "type": "Cart"}
}

Finally, the last option would allow you to keep the array structure and fire the events in order. You would need to add priorities to each child; in this case the priority would be the name of array element.

Upvotes: 3

Related Questions