1

I'm new to iOS development and wrestling with UITableViews.

My problem is that I'm populating my UITableView with data from an external server, but due to multithreading it's not waiting until the data arrives before loading the table view.

My current idea is to reload the table view when the data loads.

Earlier in same class DailyBreakdown.c, I reload the table view with this code:

-(void)viewWillAppear:(BOOL)animated
{

    [[self class] getAllActivities];

    [super viewWillAppear:animated];
    [self makeObjects];
    [self.tableView reloadData];
}

So on the callback when my data loads (using Restkit), I try to call [self.tableView reloadData] again, but I get the errors:

Definition of 'struct objc_class' must be imported from module 'ObjectiveC.runtime' before it is required

Implicit conversion of Objective-C pointer type 'Class' to C pointer type 'struct objc_class *' requires a bridged cast

Here's the method where I return the Activity objects from the API:

+(NSArray *)getAllActivities{

    if (allActivities == nil) {
        // Load the object model via RestKit
        //allActivities = [[NSMutableArray alloc] initWithObjects:@"Workout", @"Baked cake", @"Read for HR", nil];
        allActivities = [[NSMutableArray alloc] init];
        RKObjectManager *objectManager = [RKObjectManager sharedManager];

        [objectManager getObjectsAtPath:@"/activities"
                             parameters:nil
                                success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
                                    //allActivities =  [mappingResult array];
                                    allActivities = [NSMutableArray arrayWithArray: [mappingResult array]];
                                    [[self class] makeObjects];

                                    /*** THIS LINE IS THE PROBLEM **/
                                    [self.tableView reloadData];
                                }
                                failure:^(RKObjectRequestOperation *operation, NSError *error) {
                                    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                                    message:[error localizedDescription]
                                                                                   delegate:nil
                                                                          cancelButtonTitle:@"OK"
                                                                          otherButtonTitles:nil];
                                    [alert show];
                                    NSLog(@"Hit error: %@", error);
                                }];
    }

    return allActivities;

}

So, why can't I call [self.tableView reloadData] as before? How would I do this from inside my class method?

Also, is there a better way to accomplish this besides reloading the tableview? Maybe threadlocking so that allActivities doesn't return nil when the view is loaded? Any ideas are welcome.

Thanks!

Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
corbin
  • 2,797
  • 3
  • 18
  • 17

2 Answers2

1

getAllActivities is a class method, so you can't access properties and instance methods from it. The simplest solution would be to make it an instance method. In my opinion, given your situation (trying to access a tableView property) this change would be the right thing to do.

Another solutions to this problem:

  • you may add a block argument to getAllActivities that will be called when the call to external service completes successfully; in this block you would reload your table
  • you may pass your instance's self to getAllActivities and use it to access tableView

One more thing I've noticed - return allActivities; won't contain results from the last RestKit call, because it'll be executed before the call completes.

Arek Holko
  • 8,966
  • 4
  • 28
  • 46
  • Worked! Thank you! The difference between class and instance methods alludes me, so I'll have to research that. But now my tableView is being populated with server data which is a huge milestone! Thank you! – corbin Oct 05 '13 at 18:35
  • 1
    http://stackoverflow.com/a/11174572/1990236 here's quite good explanation of instance and class methods in Objective-C – Arek Holko Oct 05 '13 at 18:41
1

Your getAllActivities method is defined as a class level method (because it's prefixed with a plus). What you probably meant to do was define an instance level method (with a minus in place of the plus).

-(NSArray *)getAllActivities

The next thing I notice is that you're neither doing anything with the result from the call, nor is the result what you'd expect. Your RKObjectManager's getObjectsAtPath is asynchronous, and will return immediately. Meaning that the value for allActivities will almost always be an empty array. Therefore you can further re-define your method as:

-(void)getAllActivities{
   //...
   //No return here!
}

And, finally, since your method isn't really "getting" activities at all, you might consider naming it to something like:

-(void)reloadAllActivities
Jason Whitehorn
  • 13,585
  • 9
  • 54
  • 68