Asynchrone image download with return value required - ios

I'm trying to setup an asynchrone download of images on my application.
I'm using SDWebImage as suggested in this issue.
I put breakpoints on the progress and completed method and everything is normal. It's working perfectly but I have another problem coming from my logic directly. I don't know how to set my image asynchronously on my UIImageView.
Everything is dynamic and each image is called independently
Here is a part of my code:
[myMenu->_userAvatar setImage:[[CacheCache sharedInstance] getUIImageFromPath:currentUser.avatarPhoto.avatarURL]];
Note that CacheCache is my own cache method.
NSURL* myURL=[NSURL URLWithString:path];
//NSData* myData=[NSData dataWithContentsOfURL:myURL];
NSData* myData;
[SDWebImageDownloader.sharedDownloader downloadImageWithURL:myURL
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize)
{
DDLogInfo(#"Downloading...");
// progression tracking code
}
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished)
{
if (image && finished)
{
DDLogInfo(#"Downloaded !");
image = [[UIImage alloc] initWithData:myData];
}
}];
...
return image;
Thank you for your help.

Rather than going for that complex solution, you can try this one. Create NSObject file with name 'DownloadImagesAsynchronously' and replace .h file with following.
#import <Foundation/Foundation.h>
#protocol NotifyParentProtocol <NSObject>
-(void)ImageDownloaded:(BOOL)_isDownloaded;
#end
#interface DownloadImagesAsynchronously : NSObject{
NSMutableData *receivedData;
UIImageView *cCellImageView;
NSURLConnection *imgDownloadConnection;
id<NotifyParentProtocol> __weak delegate;
}
-(void) downloadImageAsynchornously:(NSString *)_imageURL andCellImage:(UIImageView *)_cellImgV;
#property(weak) id<NotifyParentProtocol> delegate;
#end
and replace .m with following code
#import "DownloadImagesAsynchronously.h"
#implementation DownloadImagesAsynchronously
#synthesize delegate;
- (void)loadWithURL:(NSURL *)url{
NSURLConnection *conect = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url]delegate:self];
[conect start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
[receivedData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
cCellImageView.image = [UIImage imageWithData:receivedData];
[cCellImageView.layer setCornerRadius:14.0f];
[delegate ImageDownloaded:YES];
}
-(void) downloadImageAsynchornously:(NSString *)_imageURL andCellImage:(UIImageView *)_cellImage{
cCellImageView = _cellImage;
receivedData = [[NSMutableData alloc] init];
NSString *baseURL = #"http://example.com/abc/Gallary";
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/%#",baseURL,_imageURL]];
[self loadWithURL:url];
}
#end
Now cal on your UIImageView like this, if using TableView then it will lazily download image to each tableview cell.
DownloadImagesAsynchronously *downloadAsynchImageObj = [[DownloadImagesAsynchronously alloc] init];
downloadAsynchImageObj.delegate = self;
[downloadAsynchImageObj downloadImageAsynchornously:model.ImageName1 andCellImage:self.mainImageView];
and implement delegate method. It will notify you when ever image is being downloaded. You can perform your desired action.
- (void)ImageDownloaded:(BOOL)_isDownloaded{
// Image Downloaded.
}
Hope this will work for you, if you have any question related this. Please let me know. Thanks

Thank you guys.
I mixed both of your answers. I simply passed my UIImageView to my method with asynchrone block.
Here is my code:
//view is an UIImageView coming directly from one of the parameters
if (view == nil) {
myData=[NSData dataWithContentsOfURL:myURL];
image = [[UIImage alloc] initWithData:myData];
}
else{
[SDWebImageDownloader.sharedDownloader downloadImageWithURL:myURL
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize)
{
DDLogInfo(#"Downloading...");
// progression tracking code
}
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished)
{
if (image && finished)
{
DDLogInfo(#"Downloaded !");
view.image = image;
}
}];
}
Now I only have a problem about the resize of my picture and its scale but my original issue is fixed.
I hope this will help someone else.

Related

How to update UIImages after NSURLConnection delegate completes

So I'm pulling down about 50 images from my API using NSURLConnection, its working great, except its locking up the UI when it runs. I'm assuming that is because I'm updating the UI in real time form the NSURLConnection self delegate. So I'm thinking what I need to do is put placeholder loading images in the UIImage, then update them somehow once the delegate has acquired all the data, but how do I do that, can someone give me some coding examples?
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
NSData *imageData = _dataDictionary[ [connection description] ];
if(imageData!=nil)
{
NSLog(#"%#%#",[connection description],imageData);
UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(self.x, 0, self.screenWidth, self.screenHight)];
// Process thi image
// resize the resulting image for this device
UIImage *resizedImage = [self imageScaleCropToSize:[UIImage imageWithData: imageData ]];
self.x = (self.x + imageView.frame.size.width);
if(self.x > self.view.frame.size.width) {
self.scrollView.contentSize = CGSizeMake(self.x, self.scrollView.frame.size.height);
}
[imageView setImage:resizedImage];
// add the image
[self.scrollView addSubview: imageView];
}
}
You can use SDWebImage library to achieve this.
Suppose imageArray have all the image url path.
You can use SDWebImageManager to download all the images and show them in ImageView. Also you can show downloading progress using this block.
- (void)showImages:(NSArray *)imageArray
{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
for (NSString *imagePath in imageArray)
{
[manager downloadImageWithURL:[NSURL URLWithString:imagePath]
options:SDWebImageLowPriority
progress:^(NSInteger receivedSize, NSInteger expectedSize){}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL)
{
if(!error)
self.imgView_Image.image = image;
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"please check your Connection and try again" message:#"No Internet Connection" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles: nil];
[alert show];
}
}];
}
}
First create protocol in that class .h, where you call NSURLConnection request for download image (Where you implement this method connectionDidFinishLoading).
#protocol YourClassNameDelegate <NSObject>
- (void)didFinishLoadingImage:(UIImage *)downloadImage;
#end
and create property for that protocol in same class,
#interface YourViewController : UIViewController
#property (nonatomic, retain) id<YourClassNameDelegate>delegate;
#end
then synthesise it in .m, #synthesize delegate;
After that call didFinishLoadingImage: in connectionDidFinishLoading,
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
NSData *imageData = _dataDictionary[ [connection description] ];
if(imageData!=nil)
{
NSLog(#"%#%#",[connection description],imageData);
UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(self.x, 0, self.screenWidth, self.screenHight)];
// Process thi image
// resize the resulting image for this device
UIImage *resizedImage = [self imageScaleCropToSize:[UIImage imageWithData: imageData ]];
self.x = (self.x + imageView.frame.size.width);
if(self.x > self.view.frame.size.width) {
self.scrollView.contentSize = CGSizeMake(self.x, self.scrollView.frame.size.height);
}
[self.delegate didFinishLoadingImage:resizedImage];
[imageView setImage:resizedImage];
// add the image
[self.scrollView addSubview: imageView];
}
}
and finally from where you push to YourViewController set delegate to self, like :
YourViewController *controller = [[YourViewController alloc] init];
controller.delegate = self;
//.....
in YourViewController.m, where you want to set downloaded image, in that class implement this method.
#pragma mark - YourClassName delegate method
- (void)didFinishLoadingImage:(UIImage *)downloadImage
{
//yourImageView.image = downloadImage;
}

UITableViewCell not showing image downloaded from server

I have table that is a byproduct of “Search Bar and Search Display Controller” for which the UITableViewCell is custom made from xib. Below is the code for the Cell. I am not able to spot why the image is not showing. Will someone please help me troubleshoot? All the other data are showing, except the content of the imageView.
.h
#import <UIKit/UIKit.h>
#interface BCDDogSearchTableViewCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UIImageView *dogImageView;
#property (strong, nonatomic) IBOutlet UITextView *dogDescriptionView;
#property(strong,nonatomic) NSString *imageURL;
#end
.m
#import "BCDDogTableViewCell.h"
#import "FICImageCache.h"
#interface BCDDogTableViewCell()
#property(strong,nonatomic) UIImage *image;
#end
#implementation BCDDogTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)awakeFromNib
{
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void)setImageURL:(NSString *)imageURL
{
_imageURL=imageURL;
[self startDownloadingImage];
}
-(void)startDownloadingImage
{
self.image=nil;
if (self.imageURL) {
NSLog(#"The imageURL is %#",self.imageURL);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:self.imageURL]];
NSURLSessionConfiguration *config=[NSURLSessionConfiguration ephemeralSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSURLSessionDownloadTask *task =
[session downloadTaskWithRequest:request
completionHandler:^(NSURL *localfile, NSURLResponse *response, NSError *error) {
if (!error) {
if ([request.URL isEqual:self.imageURL]) {//check in case things have changed somehow
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:localfile]];
dispatch_async(dispatch_get_main_queue(), ^{self.image=image;});//ui thread.
}
}else NSLog(#"loading image error: %#",error);
}];
[task resume];
}
}
-(void)setImage:(UIImage *)image
{
NSLog(#"set image to the image view");
self.dogImageView.image=image;
}
-(UIImage *)image
{
NSLog(#"get image from imageView");
return self.dogImageView.image;
}
-(UIImageView *) dogImageView
{
if (!_dogImageView) _dogImageView=[[UIImageView alloc]init];
return _dogImageView;
}
#end
UPDATE
I added more logging to the following snippet
if (!error) {
NSLog(#"Completion block before if");
if ([request.URL isEqual:self.imageURL]) {//check in case things have changed somehow
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:localfile]];
dispatch_async(dispatch_get_main_queue(), ^{self.image=image;});//ui thread.
}else{
NSLog(#"request url %#",request.URL);
NSLog(#"self url %#", self.imageURL);
}
}else NSLog(#"loading image error: %#",error);
And based on the logging, if ([request.URL isEqual:self.imageURL]) keeps returning false although the two urls printed in the else clause are equal in content.
So I removed that if check and suddenly the image is showing. But I am afraid it's only working because I have one row in my table. So does anyone know why the check is failing while clearly it is the same url inside?
I find the problem, in my if statement I was comparing a url with a string.
if ([request.URL isEqual:self.imageURL])
Thanks to everyone for helping.

iOS WebService doesn't seem to be starting. Anyway I can find out if its doing anything?

I have built a WebService to retrieve user specific reports using a PHP API. I am fairly new to this so I followed some tutorials and help pages to build the web service. It doesn't seem to run at all so I am thinking I stuffed up or just incorrectly put code in that didn't belong as I was following multiple tutorials etc to get the desired result.
here is the code for .m file of the web service:
#import "reportsTestViewController.h"
#import "ReportsDataObject.h"
#interface reportsTestViewController ()
#end
#implementation reportsTestViewController
#synthesize label;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.tesg.com.au/allCustBuild.php"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
//connect
label.text = #"connecting...";
} else {
//error
}
}
-(void)setupReportsFromJSONArray:(NSData*)dataFromReportsArray{
NSError *error;
NSMutableArray *reportsArray = [[NSMutableArray alloc] init];
NSArray *arrayFromServer = [NSJSONSerialization JSONObjectWithData:dataFromReportsArray options:0 error:&error];
if(error){
NSLog(#"error parsing the json data from server with error description - %#", [error localizedDescription]);
}
else {
reportsArray = [[NSMutableArray alloc] init];
for(NSDictionary *eachReport in arrayFromServer)
{
ReportsDataObject *report = [[ReportsDataObject alloc] initWithJSONData:eachReport];
[reportsArray addObject:report];
}
//Now you have your reportsArray filled up with all your data objects
}
}
-(void)connectionWasASuccess:(NSData *)data{
[self setupReportsFromJSONArray:data];
}
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
//We check against table to make sure we are displaying the right number of cells
// for the appropriate table. This is so that things will work even if one day you
//decide that you want to have two tables instead of one.
if(tableView == reportsTable){
return([theReportsArray count]);
}
return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if(cell)
{
//set your configuration of your cell
}
//The beauty of this is that you have all your data in one object and grab WHATEVER you like
//This way in the future you can add another field without doing much.
if([theReportsArray count] == 0){
cell.textLabel.text = #"no reports to show";
}
else{
ReportsDataObject *currentReport = [theReportsArray objectAtIndex:indexPath.row];
cell.textLabel.text = [currentReport buildingName];
// in the future you can grab whatever data you need like this
//[currentPlace placeName], or [currentPlace placeDay];
}
return(cell);
}
#end
and the code for the .h:
#import <UIKit/UIKit.h>
#interface reportsTestViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>{
IBOutlet UITableView *reportsTable;
IBOutlet UILabel *Label;
NSArray *theReportsArray;
}
#property (nonatomic, retain) IBOutlet UILabel *label;
#end
I'm sure it's something really ignorant that i've done but after going back through help pages and tuts, i can't find what I did wrong.
It looks like you are establishing your connection ok, but you are never handling any data that gets sent back. Once you create a connection you need to add the delegate methods to handle the data sent back by the connection.
As mentioned in some of the comments you also need to verify that your php page on the server is indeed giving you the information you expect. By logging out the data string as below in the -connectionDidFinishLoading you will be able to see any data sent back from the server for debugging.
//create an NSMutableData property in your interface
#property (nonatomic, strong) NSMutableData *myDataIvar;
//initialize it when you create your connection
if (connection){
self.myDataIvar = [[NSMutableData alloc] init];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
[self.myDataIvar setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[self.myDataIvar appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"Connection Failed: %#", error.userInfo);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
//this is where you would parse the data received back from the server
NSString *responseString = [[NSString alloc] initWithData:self.myDataIvar encoding:NSUTF8StringEncoding];
NSLog(#"Received Data: %#",responseString);
[self setupReportsFromJSONArray:self.myDataIvar];
}
This way at least you will be able to see what data you are receiving back from the server.
EDIT:
Also your test page does not seem to be putting out any json data. When I navigate to it all I get is "how".
I put up a quick php page that you can use to test your obj-c code. It will echo back an array with 10 test results to fill your tableview if your code is correct.
//Create your request pointing to the test page
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.codeyouniversity.com/json_test.php"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];
If you want to put the php on your own page for testing this is what I used.
<?php
$jsonArray = array('result1','result2','result3','result4','result5','result6','result7','result8','result9','result10');
echo json_encode($jsonArray);
?>
Here's a link to Apples documentation for the URL loading system as well
https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html#//apple_ref/doc/uid/10000165i
try this one if you get result, your url is wrong.I think now itself your url is wrong
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://api.openweathermap.org/data/2.5/weather?q=London,uk"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
//connect
label.text = #"connecting...";
} else {
//error
}
}

nsdata that are return fron NSObject class and used in viewcontroller class

I have an NSObject class that contains 3 methods:
-(void)RequestForData
{
#pragma Mark - ASIHTTPRequest
NSURL *url=[NSURL URLWithString:#"http://srv2.vitaminas.it/pdv"];
ASIHTTPRequest *request=[ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startSynchronous];
}
pragma Mark - HTTP Delegate
- (NSData*)requestFinished:(ASIHTTPRequest *)request
{
NSData *responseData = [request responseData];
return responseData;
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"%#",error);
}
I have one view controller class, from viewDidLoad method of viewcontroller class call -RequestForData method of NSObject class,
WebServiceMethods *web=[[WebServiceMethods alloc]init];
[web RequestForData];
arr_JsonData=[NSJSONSerialization JSONObjectWithData:web options:NSUTF8StringEncoding error:Nil];
NSLog(#"%#",arr_JsonData);
[self.tableView reloadData];
But I want to use NSData that are returned from NSObject class (i.e return responsedata; ) into view controller class.
I want that NSData into arr_JsonData ( NSMutuableArray )
What can I do ?
Make responseData as class level variable. Do not create local instance of it in requestFinished method.
Your problem is callbacks. You should put your viewController as a delegate of WebServiceMethods ( or using blocks is better) to be informed when the request has finished and the populate your arr_JsonData
#protocol WebServiceMethodsDelegate
- (void)webServiceMethodsDidFinishWithSucess:(NSString *)response; // give this méthode an appropriate name.
- (void)webServiceMethodsDidFailWithError:(NSError *)error;
#end
#interface WebServiceMethods : NSObject
#property (nonatomic,weak) id <WebServiceMethodsDelegate> delegate;
#end
#implemntation WebServiceMethods : NSObject
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSString *responseString = [request responseString];
[self.delegate webServiceMethodsDidFinishWithSucess:responseString];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
[self.delegate webServiceMethodsDidFailWithError:error];
}
#end
Put your viewController conform to the WebServiceMethodsDelegate protocol.
#interface yourViewController : UIViewController <WebServiceMethodsDelegate>
...
#end
and know in your the viewDidLoad of your viewController :
WebServiceMethods *web=[[WebServiceMethods alloc]init];
web.delegate = self;
[web RequestForData];
Put also the delegate methods in viewController.m
- (void)webServiceMethodsDidFinishWithSucess:(NSString *)response {
// here you can parse the response and reload your tableView
.....
[self.tableView reloadData];
}
- (void)webServiceMethodsDidFailWithError:(NSError *)error {
// handle the errors
}
PS : There are many problems with your code :
Don't use ASHTTPRequest, it's not maintained. You can use AFNetworking.AFNetworking
Put your WebServiceMethods as a shared instance.
....

Getting UITableView to populate with data from another class

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

Resources