2

So, I'm having a strange problem. I'm using Parse's iOS APIs, and using a PFQueryTableViewController to display items to the user. These items are organized into two sections. When the application first starts, it runs the objectsDidLoad method BEFORE it runs the numberOfRowsInSection method. This is perfect because the objectsDidLoad method is able to define the number of objects present in each section of the table view. I am also enabling the tableView's "pull-down to refresh" capabilities, which is working perfectly. So, if I change a certain data value on my parse data browser, this should cause one of the items being displayed to the user to change sections. If I restart the app after changing that data value, the object appears in the other section like it should. The problem, however, is if I change the data value on parse to cause the object to change sections, and then pull down the tableView to refresh the data, the app crashes and I think I know why. Although the objectsDidLoad method executes BEFORE the numberOfRowsInSection method the first time the app runs, it actually executes AFTER the numberOfRowsInSection when I pull down the tableView and refresh the data. This causes the cellForRowAtIndexPath method to attempt to access an array index that doesn't exist in the arrays storing the objects in each section.

My question: How do I refresh the objects and update the arrays storing the objects for each section BEFORE the numberOfRowsInSection method gets called?

Here's my objectsDidLoad method:

    - (void)objectsDidLoad:(NSError *)error {
       //dataArray, firstSectionArray, and secondSectionArray are global NSMutableArrays
       [super objectsDidLoad:error];

       firstSectionArray = [[NSMutableArray alloc]init];
       secondSectionArray = [[NSMutableArray alloc]init];
       NSMutableDictionary *firstSectionDictionary = [[NSMutableDictionary alloc]init];
       NSMutableDictionary *secondSectionDictionary = [[NSMutableDictionary alloc]init];
       dataArray = [[NSMutableArray alloc]init];

       for (int i = 0; i < [self.objects count]; i++) {
           if ([[[self.objects objectAtIndex:i]objectForKey@"Level"]intValue] == 1) {
               [firstSectionArray addObject:[self.objects objectAtIndex:i]];
           }
           else {
               [secondSectionArray addObject:[self.objects objectAtIndex:i]];
           }
       }

       firstSectionDictionary = [NSMutableDictionary dictionaryWithObject:firstSectionArray forKey:@"data"];
       secondSectionDictionary = [NSMutableDictionary dictionaryWithObject:secondSectionArray forKey:@"data"];
       [dataArray addObject:firstSectionDictionary];
       [dataArray addObject:secondSectionDictionary];
    }

Here's my numberOfRowsInSection method:

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        NSDictionary *dictionary = [dataArray objectAtIndex:section];
        NSMutableArray *array = [dictionary objectForKey:@"data"];
        return [array count];
    }

Here's my cellForRowAtIndexPath method:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
        static NSString *CellIdentifier = @"Cell";

        PFTableViewCell *cell = (PFTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
        }

        NSMutableDictionary *dictionary = [dataArray objectAtIndex:indexPath.section];
        //This next line is where it's crashing
        PFObject *newObject = [[dictionary objectForKey:@"data"]objectAtIndex:indexPath.row];

        //More irrelevant code below..........
    }

2 Answers 2

3

I have fixed the issue by multithreading my app. I've used a global BOOL called isDoneLoading to check whether or not the objectsDidLoad method has completed executing. Here's my objectsDidLoad method:

- (void)objectsDidLoad:(NSError *)error {
     [super objectsDidLoad:error];

     dataArray = [[NSMutableArray alloc]init];

     NSMutableArray *firstSectionArray = [[NSMutableArray alloc]init];

     NSMutableArray *secondSectionArray = [[NSMutableArray alloc]init];

     for (int i = 0; i < [self.objects count]; i++) {
         //First Section
         if ([[[self.objects objectAtIndex:i]objectForKey:@"Level"]intValue] == 1) {
             [firstSectionArray addObject:[self.objects objectAtIndex:i]];
         }
         //Second Section
         else  {
             [secondSectionArray addObject:[self.objects objectAtIndex:i]];
             /*} else {
              //Other Sections
              [secondSectionArray addObject:[self.objects objectAtIndex:i]];
              }*/
         }
     }

     NSMutableDictionary *firstSectionDictionary = [NSMutableDictionary dictionaryWithObject:firstSectionArray forKey:@"data"];
     [dataArray addObject:firstSectionDictionary];

      NSMutableDictionary *secondSectionDictionary = [NSMutableDictionary dictionaryWithObject:secondSectionArray forKey:@"data"];
     [dataArray addObject:secondSectionDictionary];

     isDoneLoading = true;
 }

Here's my numberOfRowsInSection method:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    dispatch_group_t d_group = dispatch_group_create();
    dispatch_queue_t bg_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    __block NSDictionary *dictionary;
    __block NSMutableArray *array;

    dispatch_group_async(d_group, bg_queue, ^{
       // [self queryForTable];
        [self objectsDidLoad:NULL];
        while (!isDoneLoading) {}

        dictionary = [dataArray objectAtIndex:section];
        array = [dictionary objectForKey:@"data"];
    });

    dispatch_group_wait(d_group, DISPATCH_TIME_FOREVER);

    isDoneLoading = false;
    return [array count];
}

Using this method of multithreading, I am capable of always preventing the numberOfRowsInSection method from executing before the objectsDidLoad method.

Sign up to request clarification or add additional context in comments.

1 Comment

Dope. A much needed thingy. I'm having exact same problem.
0

Add this At the end of your objectsDidLoad Method

if(self.tableView.numberOfSections != self.sections.allKeys.count)
    {
        [self.tableView reloadData];
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.