0

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?

3
  • Are the methods numberOfSectionsInTableView, numberOfRowsInSection and cellForRowAtIndexPath being called? Commented May 1, 2013 at 9:07
  • Hi The Dude, to answer your question, yes the table view is being called from a UIButton. In fact l had this app originally working, but the NSRUL connection delegate methods where all located within my ViewController 'DropletsList'. I then broke out the model into a separate class. Commented May 1, 2013 at 11:42
  • I think you should follow Anupdas advice, it seems it has to do with network connection. Commented May 1, 2013 at 12:23

1 Answer 1

0
- (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 :)

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

19 Comments

Hi Anupdas, thank you for your comments, could you give me an example of a 'callback', in relation to my classes?
@user1992953 I have edited my answer. It will get you started.
Anupdas, you are a star! So just to clarify, obviously your example used a single class method, therefore if l wanted to conform to the NSURLConnectionDelegate, what would l need to do differently?
@user1992953 Nice to hear that. If you are using NSURLConnectionDelegate, you will have to make a delegate of Droplet and the controller which needs to be triggered on completion of event should implement the delegate. It is more effort than it's worth. You will make it more complicated in the process.
@user1992953 Any follow up on the issue ?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.