1

I use parse.com as backend, and my query was very slow, so I am trying to change it to use blocks.

Basically, my query populates an array with everything I need, and according to if statements, I'm calling methods inside the block, these methods populate the array that I will use in cellForRowAtIndexPath. The problem is that when I try to reloadDatainside block, the app crashes.

Here is the code:

- (void)queryForTable {
    PFQuery *exerciciosQuery = [PFQuery queryWithClassName:@"ExerciciosPeso"];
    [exerciciosQuery whereKey:@"usuario" equalTo:[PFUser currentUser]];
    [exerciciosQuery includeKey:@"exercicio"];

    exerciciosQuery.cachePolicy = kPFCachePolicyCacheElseNetwork;

    [exerciciosQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {

         [self configurarDatas];

         _seriesArray = objects;

            if (_seriesArray.count > 0) {
                NSPredicate *predIniciante = [NSPredicate predicateWithFormat:@"serie contains [cd] %@", @"Ini"];
                NSArray *arrayIniciante = [_seriesArray filteredArrayUsingPredicate:predIniciante];


                NSArray *arrayInicianteApenasSeries = arrayIniciante;
                NSArray *arrayInicianteApenasSeries2 = [arrayInicianteApenasSeries valueForKey:@"serie"];
                NSSet *setInicianteApenasSeries = [NSSet setWithArray:arrayInicianteApenasSeries2];
                NSArray *arrayInicianteCount = [setInicianteApenasSeries allObjects];

                if (arrayInicianteCount.count > 0) {
                    [self popularSeriesInicianteAB];
                // [self.tableView reloadData];


                }
                else if (arrayInicianteCount.count > 8) {

                    [self popularSeriesInicianteC];
                    //   [self.tableView reloadData];

                }
                else {

                    [self popularSeriesAvancado];
                    //   [self.tableView reloadData];
                    NSLog(@"POPULAR SERIES AVANÇADO");
                }
            }
    }];

}

I have also tried to reloadData using dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });, but it didn't work as well.

Anyway, I imagine that if I erase my methods and put everything inside the block, it will work, but I don't want to do that, as calling methods using if make my code easier to follow.

UPDATE:

For completeness, here are my DataSource methods:

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
     {
     NSLog(@"numberOfRowsInSection %li", (unsigned long)_seriesForDisplay.count);
     return _seriesForDisplay.count;

 }


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

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





    PFObject *o = _seriesForDisplay[indexPath.row];
    // Texto da célula
    cell.textLabel.text = o[@"serieDisplay"];

    cell.detailTextLabel.text = o[@"grupos"];



    return cell;

}
Jorge
  • 1,492
  • 1
  • 18
  • 33
  • Not your issue (yet) but `[self popularSeriesInicianteC];` never gets called. – Rok Jarc Jan 06 '14 at 14:27
  • And try this: http://stackoverflow.com/a/7914335/653513 should work if you don't have your `populate...` methods also working in background. If so, call the `reloadData` when they finish... - no sooner. – Rok Jarc Jan 06 '14 at 14:29
  • I tried this, but got the crash with message: index 0 beyond bounds for empty array'. I tried to use this code inside the block. When I log the arrays inside the block, it seems like the methods are correctly populating the array. – Jorge Jan 06 '14 at 15:10
  • Can you post code of your `populate...` methods. It seems they are also working on separate thread... OR: how are you passing data to those methods? Are they working with `nil` data by any chance? – Rok Jarc Jan 06 '14 at 15:15
  • I just edited the question, it was missing the line `_seriesArray = objects;`. This `NSArray`property is the one I use in the `populate...`methods. – Jorge Jan 06 '14 at 15:19
  • When I log any array inside the block, it is correctly populated, meaning the methods are working. – Jorge Jan 06 '14 at 15:20
  • Ok, when you log it inside block. What about inside `populate...` methods? Try `_seriesArray = [NSArray arrayWithArray:objects;]` – Rok Jarc Jan 06 '14 at 15:22
  • When I log inside `populate...`methods it also shows the correct count. I just tried `[self.tableview reloadData];`inside block, and it shows the log I have in `numberOfRowsInSection`with correct count, this shows just before crash. – Jorge Jan 06 '14 at 15:27
  • same result with `dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; });`inside block. – Jorge Jan 06 '14 at 15:29
  • 1
    What is this `- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object`? Strange signature for `dataSource` delegate method... Try simply: `- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath` – Rok Jarc Jan 06 '14 at 15:38

3 Answers3

2

There are 2 way to implement data in tableview with Parse SDK

  1. PFqueryTableViewController: you need implement

    - (PFQuery *)queryForTable {
         return query;
      }
    
    - (PFObject *)objectAtIndex:(NSIndexPath *)indexPath {
      // overridden, since we want to implement sections
      }
    
     - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: 
       (NSIndexPath *)indexPath object:(PFObject *)object {
      //get data: object
      }
    
     - (UITableViewCell *)tableView:(UITableView *)tableView cellForNextPageAtIndexPath:
     (NSIndexPath *)indexPath 
    
  2. UITableViewController/ UITableview in UIViewController:
    This is normal way, implement uitableview delegate/datasource, you can write a method like (void)queryForTable and call reloadData in here.

HoanNguyen
  • 405
  • 2
  • 12
  • I tried this, but got the crash with message: index 0 beyond bounds for empty array'. When I try to reloadData the array is still empty. I tried to use this code inside the block. – Jorge Jan 06 '14 at 15:11
  • your problem is not from reloadData in mainthread or background thread, I think it from your datasource. Show me more code: yourarray, numberRowAtIndexpath, cellForRowAtIndexPath – HoanNguyen Jan 06 '14 at 15:30
  • 2
    Are you using PFQueryTableViewController? So you need implement a (PFQuery)queryForTable not (void). you should use a normal uitableview than PFquerytableview if you stil not clear it – HoanNguyen Jan 06 '14 at 15:40
2

I was using PFQueryTableViewController, which is from parse.com backend and has some different methods. I changed my query to void and used findObjectsInBackgroundWithBlock. Therefore, my method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object, was not receiving the PFObjects, that's why I was getting a crash when tried to reloadData.

I changed my table back to UITableViewController.

I'm using dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; }); inside block and it's working now.

Great answers to this post, helped me a lot.

Jorge
  • 1,492
  • 1
  • 18
  • 33
  • `PFQueryTableViewController` is an important piece of information :) Good to hear you've got it working. – Rok Jarc Jan 06 '14 at 15:53
1

If you can't guarantee what thread a block will be run on (if it can run on a background thread) then you should switch to the main thread before actioning any UI changes. This could be done with performSelectorOnMainThread:withObject:waitUntilDone: or dispatch_async(dispatch_get_main_queue(), ^{.

Wain
  • 118,658
  • 15
  • 128
  • 151
  • When I switch to main thread to reloadData, I get the crash saying that my array is empty. – Jorge Jan 06 '14 at 15:13
  • When you reload you should be using the same array for getting the row count and getting the cell data... – Wain Jan 06 '14 at 15:47