Getting UITableView to populate with data from ano

2019-04-17 07:47发布

问题:

I am quite new to Objective-C and this is the first time I have attempted to implement MVC. I have a model class where l have an NSArray which will be populated with data from a JSON object. I want to populate my UITableView (in my view controller class), with objects from this array.

Please review my code:

Droplets.h

@interface Droplets : NSObject {
    NSArray *dropletsArray;

}

// Get droplets data
- (void) getDropletsList;

//Object initilization
- (id) init;

//Public properties
@property (strong, nonatomic) NSArray *dropletsArray; // Used to store the selected JSON data objects

@end

Droplets.m

#define kBgQueue dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define kDigialOceanApiURL [NSURL URLWithString:@"http://inspiredwd.com/api-test.php"] //Droplets API call

#import "Droplets.h"

@interface Droplets ()

//Private Properties
@property (strong, nonatomic) NSMutableData *data; // Used to store all JSON data objects
@end


@implementation Droplets;

@synthesize dropletsArray;
@synthesize data;

- (id)init
{
    self = [super init];
    if (self) {

    }
    return self;
}

- (void) getDropletsList {

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    NSURL *url = kDigialOceanApiURL; // Predefined Digital Ocean URL API http request
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [NSURLConnection connectionWithRequest:request delegate:self]; //Should be: [[NSURLConnection alloc]initiWithRequest:request delegate:self]; ...however the instance of NSURLConnection is never used, which results in an "entity unsed" error.
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

    data = [[NSMutableData alloc]init]; // mutable data dictionary is allocated and initilized
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData {

    [data appendData:theData]; // append 'theData' to the mutable data dictionary
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

    //JSON foundation object returns JSON data from a foundation object. Assigned returned data to a dictionary 'json'.
    NSDictionary* jsonData = [NSJSONSerialization JSONObjectWithData:data
                                                             options:kNilOptions error:0];

    self.dropletsArray = [jsonData objectForKey:@"droplets"]; //dictionary of arrays
    NSLog(@"Droplets %@", self.dropletsArray);
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    // If the application is unable to connect to The Digital Ocean Server, then display an UIAlertView
    UIAlertView *errorView = [[UIAlertView alloc]initWithTitle:@"Error" message:@"Unable to connect to The Digital Ocean Server, please ensure that you are connected via either WIFI or 3G." delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];

    [errorView show];

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; // Turn of the network activity indicator
}

@end

DropletsList.h

    @class Droplets;

    @interface DropletsList : UITableViewController 

    - (Droplets *) modelDroplets;

    @end

DropletsList.m

    #define RGB(r, g, b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]

    @interface DropletsList ()

    //Private properties
    @property (strong, nonatomic) Droplets *modelDroplets;
    @property (strong, nonatomic) NSArray *tableData;

    @end

@implementation DropletsList

@synthesize tableData;

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
        NSLog(@"get my data from model");
    }
    return self;
}

- (Droplets *) modelDroplets
{
    if (!_modelDroplets) _modelDroplets = [[Droplets alloc]init];
    return _modelDroplets;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    _modelDroplets = [[Droplets alloc]init];
    self.tableData = [_modelDroplets dropletsArray];
    [_modelDroplets getDropletsList];

    [self.tableView reloadData]; // reload the droplets table controller

}


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source


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

    return 1; // Return the number of sections.

}


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

    return [_modelDroplets.dropletsArray count]; // Return the number of rows in the section.
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // The cell identified by "dropletsList", is assiged as the UITableViewCell
    UITableViewCell *cell = [tableView
                             dequeueReusableCellWithIdentifier:@"dropletsList"];

    //NSLog(@"Droplets Name: %@",self.dropletsArray);

    // The UITableView text label is assigned the contents from 'dropletsArray', with the object key "name"- name of the droplet
    cell.textLabel.text=[[tableData objectAtIndex:indexPath.row]objectForKey:@"name"];

    // The UITableView text detail label is assigned the contents from 'dropletsArray', with the object key "status"- status of the droplet
    cell.detailTextLabel.text=[[tableData objectAtIndex:indexPath.row]objectForKey:@"status"];

    //Evalulate the status of each droplet, setting the colour appropriate to the staus
    if ([[[tableData objectAtIndex:indexPath.row] objectForKey:@"status"] isEqualToString:@"active"]) {

        //Set the detail text label colour
        cell.detailTextLabel.textColor = RGB (35,179,0);
    }
    return cell;

}

@end

Basically my table doesn't populate. Please could someone help?

回答1:

- (void)viewDidLoad
{
    [super viewDidLoad];
    _modelDroplets = [[Droplets alloc]init];
    self.tableData = [_modelDroplets dropletsArray];
    [_modelDroplets getDropletsList];

    [self.tableView reloadData]; // reload the droplets table controller

}

In this method you are fetching droplets from a webservice. It is asynchronous, by the time tableView reloads the data it might not have completed fetching the data. You need to have a callback which will reload the tableView on completion of webservice.

EDIT :

Create a class method in Droplets to fetch all data

//Droplets.h
typedef void (^NSArrayBlock)(NSArray * array);
typedef void (^NSErrorBlock)(NSError * error);

//Droplets.m
+ (void)getDropletsWithCompletion:(NSArrayBlock)arrayBlock onError:(NSErrorBlock)errorBlock
{
    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:kDigialOceanApiURL];
    [urlRequest setHTTPMethod:@"GET"];
    [urlRequest setCachePolicy:NSURLCacheStorageNotAllowed];
    [urlRequest setTimeoutInterval:30.0f];
    [urlRequest addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

    [NSURLConnection sendAsynchronousRequest:urlRequest
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *responseData, NSError *error) {

                               if (error) {
                                   errorBlock(error);
                               }else{
                                   NSError *serializationError = nil;
                                   NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData
                                                                                        options:NSJSONReadingAllowFragments
                                                                                          error:&serializationError];

                                   arrayBlock(json[@"droplets"]);
                               }

                           }];

}

//DropletsList.h

- (void)viewDidLoad
{
    [super viewDidLoad];

    [Droplets getDropletsWithCompletion:^(NSArray *array) {
          self.modelDroplets = droplets;
          [self.tableView reloadData];
     } onError:^(NSError *error) {

           UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Error" message:error.localizedDescription delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
           [alert show];
    }];

}

Disclaimer : Tested and verified :)