(Parse.com) Loading PFObjects into Array?

Discussion in 'iOS Programming' started by Danneman101, Jan 28, 2012.

  1. Danneman101 macrumors 6502

    Joined:
    Aug 14, 2008
    #1
    I'm using Parse.com's solution for databases, and want to load db-table into a UITable. I'm trying to accomplish this by first creating an array, then loading the database-table into that array, and finally loading the array into the UITable.

    Code:
    - (void)setupArray
    {
        dummyArray = [[NSMutableArray alloc] init];
    
        PFQuery *query = [PFQuery queryWithClassName:@"Events"];
        [query findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) {
            for (PFObject *comment in comments) 
            {
                PFObject *post = [comment objectForKey:@"event"];            
                [dummyArray addObject:post];
            }
        }];
    }
    
    
    - (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.text = [dummyArray objectAtIndex:indexPath.row];
        
        return cell;
    }
    
    However, nothing is shown in the UITable.

    Could this be because the database does not have time to be retrieved before the "cellForRowAtIndexPath" is called (and thus is empty when cycling trough and setting up each cell)?

    Or is my syntax wrong?

    Alternatively, is there a better way of doing this?
     
  2. Danneman101, Jan 28, 2012
    Last edited: Feb 2, 2012

    Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #2
    Yes, it was simply too slow to load. Instead I loaded the array in the AppDelegate immediately when the app was loaded, and then accessed it from the tableview-code.

    Code:
        // Get:     AppDelegate
        AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
        
        // Set:     Cell from AppDel>dummyArray
        cell.textLabel.text = [appDelegate.dummyArray objectAtIndex:indexPath.row];
    
     
  3. jamesjyu macrumors newbie

    Joined:
    Feb 3, 2012
    #3
    James here from Parse.

    You were actually on the right track in your first example. The reason your table isn't showing any data is because setupArray is firing off an async request to get the objects and load the array. However, the UITableView is reading the array before the the callback from Parse is executed.

    The right way to do this is to call reloadData on the table in the PFQuery block.

    Hope this helps!
     
  4. Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #4
    Thanks for the reply! Yes, that was how I had already solved it :)

    Function in AppDelegate:
    Code:
    - (void)setupArray
    {
        // Set:     Bool (stops other calls being made to this function while it's running)
        B_setupArrayIsRunning = YES;
        
        // Init:    Array to hold the data retrieved
        eventArray          = [[NSMutableArray alloc] init];
    
        // Get:     DB from Parse.com
        PFQuery *query = [PFQuery queryWithClassName:str_ParseTableName];       // Get:     Class name from Parse.com
        [query orderByDescending:@"createdAt"];                                 // Order:   By most recent
        query.limit = [NSNumber numberWithInt:n_MaxNrEvents];                   // Get:     Only 10 most recent
        __block int counter = 0;
        [query findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) 
        {
            for (PFObject *comment in comments) 
            {           
                // Event
                PFObject *post = [comment objectForKey:@"event"];               // Get:     From Column "event"
                if (post == nil) { post = @" "; }                 // Save:    Empty string if no data in current tablerow
                [eventArray insertObject:post atIndex:counter];                 // Save:    DB-data to array
                
                counter ++;
            }
            
            // Lets AppDel access SecondViewController where the table is (this app uses storyboard and is a tabbarapplication)
            UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;            // GET: TabBarCtrl ->
            UINavigationController *navigationController = [[tabBarController viewControllers] objectAtIndex:1];    // GET: Second NavCtrl ->
            SecondViewController *secondVC = [[navigationController viewControllers] objectAtIndex:0];              // GET: SecondVC 
    
            // Reload:      Tableview
            [secondVC.myTableView reloadData];
            
            
            // Reset:       Bool (enables other calls being made to this function)
            B_setupArrayIsRunning = NO;
        }];
    }
    
    I realized that if I didn't restrict access to this function (using the B_setupArrayIsRunning-var) it could be called more than once before the full table had been saved into the array. This resulted in duplicated posts in the array. Another side-effect of the async request, but using the boolean solves this.
     

Share This Page