0

I am trying to retrieve values from Firebase and then perform operations on them. However, it seems like those values are only staying assigned inside of the function call. My code looks like this:

self.ref = [[FIRDatabase database] reference];

[[_ref child:@"user"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
      // Get all user wishlists
        self.wishLists = [[NSMutableDictionary alloc] initWithDictionary:snapshot.value[@"wishlist"]];

        NSLog(@"%@", self.wishLists);

    } withCancelBlock:^(NSError * _Nonnull error) {
      NSLog(@"%@", error.localizedDescription);
    }];

    NSLog(@"%@", self.wishLists);

    for(id key in self.wishLists){
        wishList *newList = [wishList new];
        newList.name = key;
        NSLog(@"%@", newList.name);
        [self.listArray addObject:newList];
    }

where self.wishLists is defined as follows: @property (strong) NSMutableDictionary *wishLists; The first NSLog call to print wishList successfully prints out the value, but the second one does not, indicating that somehow self.wishLists is null even though I assigned it to the value that I pulled from Firebase. How can I keep that value assigned outside the function?

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Any code that needs access to the data from the database will need to be inside the completion handler (that is called when that data is available), or be called from within the completion handler. – Frank van Puffelen May 12 '20 at 23:01

1 Answers1

0

Data is loaded from Firebase asynchronously since it may need to come from the server. While this is happening, your main code continues to execute, so that the user isn't blocked from using the app. Then when the data is loaded, your completion handler is called.

For this reason, any code that needs access to the data from the database will need to be inside the completion handler (that is called when that data is available), or be called from within the completion handler.

So the simplest way to fix the problem is to move your loop into the completion handler:

self.ref = [[FIRDatabase database] reference];

[[_ref child:@"user"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
      // Get all user wishlists
        self.wishLists = [[NSMutableDictionary alloc] initWithDictionary:snapshot.value[@"wishlist"]];

        NSLog(@"%@", self.wishLists);

        NSLog(@"%@", self.wishLists);

        for(id key in self.wishLists){
            wishList *newList = [wishList new];
            newList.name = key;
            NSLog(@"%@", newList.name);
            [self.listArray addObject:newList];
        }

    } withCancelBlock:^(NSError * _Nonnull error) {
      NSLog(@"%@", error.localizedDescription);
    }];

If you want to keep the code that loads the data separate from the code that uses it, you could define your own completion handler too. For an example of that, see getting data out of a closure that retrieves data from firebase

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807