Search code examples
iosobjective-cnsurlnsurlrequest

Problems loading Table View with data retrieved using NSURL


I'm still new to using NSURL to get data and seem to have issues whenever trying to use this. In this case I use debug to check all the date coming in in ViewDidload and all the correct data comes in and is split into the arrays I then want to use to build my table view controller. However when we reach the NumberOfRows in section method, all of the arrays seem to have been reset to nil. I've tried using various combinations of NSURL solutions but none seem to get any further than the one I am using right now (which at least shows some data arrriving). Can anyone please let me know if I am making an obvious mistake, or if not give me a reliable piece of code which I should use to perform a simple GET like this. Thank you very much.

Here below my code:

@implementation MyLessonsTableViewController

    NSArray *pastarr = nil;
    NSArray *todoarr = nil;
    NSArray *comingarr = nil;
    NSArray *jsonless = nil;


- (void)viewDidLoad {
    [super viewDidLoad];


    // GET MY LESSONS FROM DATABASE

    jsonless = [[NSArray alloc] init];
    pastarr = [[NSArray alloc] init];
    todoarr = [[NSArray alloc] init];
    comingarr = [[NSArray alloc] init];

    NSString  *token = @"5cfd28bed3f5f5bd63143c81a50d434a";
    NSString *urlString = [NSString stringWithFormat:@"http://soon.nextdoorteacher.com/apps/api/nextdoorteacher/student-lessons?t=%@", token];

    NSURL *urlcc = [NSURL URLWithString:urlString];
    NSData *data = [NSData dataWithContentsOfURL:urlcc];
    NSError *error;
    NSMutableDictionary *jsonLess = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
                                                                    error:&error];

    dispatch_async(dispatch_get_main_queue(), ^{
    [self.tableView reloadData];
    });

    NSLog(@"My Lessons Json == %@", jsonLess);

  // SPLIT ARRAY

    NSArray *pastarr = [jsonLess valueForKeyPath:@"past"];
    NSArray *todoarr = [jsonLess valueForKeyPath:@"todo"];
    NSArray *comingarr = [jsonLess valueForKeyPath:@"upcoming"];



- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    // Return the number of sections.
    return 3;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    // Return the number of rows in the section.
    NSUInteger lessonRowCount = 0;
    switch (section) {
        case 0:
            lessonRowCount = todoarr.count;
            break;
        case 1:
            lessonRowCount = comingarr.count;
            break;
        case 2:
            lessonRowCount = pastarr.count;
            break;

        default:
            break;

    }

    return lessonRowCount;

}

Solution

  • Several issues.

    1. You call reloadData needlessly in dispatch_async.
    2. You call reloadData before you process jsonLess.
    3. You never assign anything to your array ivars.
    4. You don't actually have ivars for your arrays. You have global variables.

    Here's your posted code all fixed up:

    @implementation MyLessonsTableViewController {
        NSArray *pastarr = nil;
        NSArray *todoarr = nil;
        NSArray *comingarr = nil;
    }    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // GET MY LESSONS FROM DATABASE
        NSString *token = @"5cfd28bed3f5f5bd63143c81a50d434a";
        NSString *urlString = [NSString stringWithFormat:@"http://soon.nextdoorteacher.com/apps/api/nextdoorteacher/student-lessons?t=%@", token];
    
        NSURL *urlcc = [NSURL URLWithString:urlString];
        NSData *data = [NSData dataWithContentsOfURL:urlcc];
        NSError *error;
        NSMutableDictionary *jsonLess = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
                                                                        error:&error];
    
        NSLog(@"My Lessons Json == %@", jsonLess);
    
        // SPLIT ARRAY
        pastarr = [jsonLess valueForKeyPath:@"past"];
        todoarr = [jsonLess valueForKeyPath:@"todo"];
        comingarr = [jsonLess valueForKeyPath:@"upcoming"];
    
        [self.tableView reloadData];
    }
    

    Now this still suffers from one big problem. You are doing Internet access on the main thread. That's bad. You really should do it this way:

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // GET MY LESSONS FROM DATABASE
        NSString *token = @"5cfd28bed3f5f5bd63143c81a50d434a";
        NSString *urlString = [NSString stringWithFormat:@"http://soon.nextdoorteacher.com/apps/api/nextdoorteacher/student-lessons?t=%@", token];
    
        NSURL *urlcc = [NSURL URLWithString:urlString];
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSData *data = [NSData dataWithContentsOfURL:urlcc];
            NSError *error;
            NSMutableDictionary *jsonLess = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
                                                                        error:&error];
    
            NSLog(@"My Lessons Json == %@", jsonLess);
    
            // SPLIT ARRAY
            pastarr = [jsonLess valueForKeyPath:@"past"];
            todoarr = [jsonLess valueForKeyPath:@"todo"];
            comingarr = [jsonLess valueForKeyPath:@"upcoming"];
    
            // Now this must be done on the main thread
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.tableView reloadData];
            });
        }};
    }