How to load images from API/URL asynchronously? - ios

I am fetching images synchronously from an array which stores URLs of images but it work very slowly. Now i want to load them asynchronously for fast working.
Heres the code and provide answer with coding.
#import "DetailViewController.h"
#import "FinalViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
#synthesize jsonData;
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Select a Photo";
// Do any additional setup after loading the view.
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURL *url = [NSURL URLWithString:#"http://json.code.com/albums/1/photos"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response
{
data1 = [[NSMutableData alloc] init];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)theData
{
[data1 appendData:theData];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
jsonArray1 = [NSJSONSerialization JSONObjectWithData:data1 options:nil error:nil];
[mainTableView reloadData];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(nonnull NSError *)error
{
UIAlertView *errorView = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Please make sure you are connected to either 3G or Wi-Fi." delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil, nil];
[errorView show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (int)numberOfSectionInTableView:(UITableView *)tableView
{
return 1;
}
- (int) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [jsonArray1 count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
cell.textLabel.text = [[jsonArray1 objectAtIndex:indexPath.row] objectForKey:#"title"];
cell.detailTextLabel.text = [NSString stringWithFormat:#"URL : %#", [[jsonArray1 objectAtIndex:indexPath.row] objectForKey:#"url"]];
NSURL *URL = [[NSURL alloc] initWithString:[[jsonArray1 objectAtIndex:indexPath.row] valueForKey:#"thumbnailUrl"]];
NSData *URLData = [[NSData alloc] initWithContentsOfURL:URL];
[[cell imageView]setImage:[UIImage imageWithData:URLData]];
return cell;
}
-(void)tableView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
FinalViewController *fvc = [[FinalViewController alloc] initWithNibName:#"FinalViewController" bundle:nil];
fvc.jsonData2 = [jsonArray1 objectAtIndex:indexPath.row];
[self.navigationController pushViewController:fvc animated:YES];
}
#end

We can use dispatch_async to run the operation asynchronously.
Try this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
myCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
cell = [[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.poster.image = nil; // or cell.poster.image = [UIImage imageNamed:#"placeholder.png"];
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://myurl.com/%#.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:#"movieId"]]]];
if (imgData) {
UIImage *image = [UIImage imageWithData:imgData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
myCell *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath];
if (updateCell)
updateCell.poster.image = image;
});
}
}
});
return cell;
}

You can do like this:
cell.tag = indexPath.row;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^(void) {
NSData *imageData = [NSData dataWithContentsOfURL: URL];
UIImage* image = [[UIImage alloc] initWithData:imageData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
if (cell.tag == indexPath.row) {
cell.imageView.image = image;
[cell setNeedsLayout];
}
});
}
});
Ref: Asynchronous downloading of images for UITableView with GCD

Just by simply setting the following works fine for me .
cell.imageView.image =[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[imageArray objectAtIndex:i]]]]];
You can use the activity indicator as you have asked . Just drag and drop UIActivityIndicatorView onto the UIImageView of the UITableViewCell and set the needed constraints . Once the image gets loaded you can set it as hidden .
To do it programmatically , you can add a subview to the Image view in the UITableViewCell. Once the Image gets loaded you can remove the sub view .
UIActivityIndicatorView* actInd = [[UIActivityIndicatorView alloc]init];
[cell.imageView addSubview:actInd];

Related

How to use SDWebImage

I have UITableViewCell and in this load images, so I want to images load Asynchronies and show activate indicator. This time images loading time is very high and all images load after images show on table view. many times images cant load and user UIInterface is hang. and do not work any process in application.. I am very tired, I used a SDWebImage library. please help how it possible, Thank You
#import "UIImageView+WebCache.h"
#interface pictureViewController ()
{
NSArray*picarray;
NSArray*titlearray;
NSArray*idarray;
}
#end
#implementation pictureViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[[self navigationController] navigationBar] setTitleTextAttributes:#{NSForegroundColorAttributeName: [UIColor whiteColor]}];
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"background2.png"] forBarMetrics:UIBarMetricsDefault];
_tableview.separatorColor = [UIColor yellowColor];
NSURLRequest *req=[[NSURLRequest alloc]initWithURL:[NSURL URLWithString:#"http://edutimeapp.com/toshow/chamber-of-commerc/ws/fetch_gallery.php"]];
response =[[NSMutableData alloc]init];
[NSURLConnection connectionWithRequest:req delegate:self];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[response appendData:data];
NSLog(#"error receving data %#",response);
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *error;
//NSLog(#"Error in receiving data %#",error);
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableLeaves error:&error];
// NSLog(#"response data %#",json);
NSArray *results = [json objectForKey:#"status"];
picarray = [results valueForKey:#"img_url"];
titlearray = [results valueForKey:#"title"];
// NSLog(#"my title is%#",titlearray);
idarray=[results valueForKey:#"id"];
//NSLog(#"my galary id is%#",idarray);
[self.tableview reloadData];
}
// Do any additional setup after loading the view, typically from a nib.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [picarray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// NSLog(#"tableview cell");
picture_viewcontrollerCell *cell = [tableView dequeueReusableCellWithIdentifier:#"htr"];
if (cell==nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"Cell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
//NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString: [picarray objectAtIndex:indexPath.row]]];
// UIImage* image = [[UIImage alloc] initWithData:imageData];
//cell.picture.image =image;
cell.titlelbl.text=[NSString stringWithFormat:#"%#",[titlearray objectAtIndex:indexPath.row]];
NSURL*url= [[picarray objectAtIndex:indexPath.row]valueForKey:#"img_url"];
[cell.picture setContentMode:UIViewContentModeScaleAspectFill];
[cell.picture sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:#"Placeholder.jpg"]];
return cell;
}
#end
You should try this (Show activityIndicator & Load Image using SDWebImage)-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// NSLog(#"tableview cell");
picture_viewcontrollerCell *cell = [tableView dequeueReusableCellWithIdentifier:#"htr"];
if (cell==nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"Cell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.titlelbl.text=[NSString stringWithFormat:#"%#",[titlearray objectAtIndex:indexPath.row]];
NSURL*url= [NSURL URLWithString:[NSString stringWithFormat:#"%#",[picarray objectAtIndex:indexPath.row]]];
[cell.picture setContentMode:UIViewContentModeScaleAspectFill];
[cell.picture setShowActivityIndicatorView:YES];
[cell.picture setIndicatorStyle:UIActivityIndicatorViewStyleGray];
[cell.picture sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:#"placeHolder.png"] options:indexPath.row == 0 ? SDWebImageRefreshCached : 0];
return cell;
}
Are you sure your code can even compile? In your cellForRowAtIndexPath I see [cell.picture sd_setImageWithURL:imageData placeholderImage:[UIImage imageNamed:#"Placeholder.jpg"]];
when you commented off your declaration of imageData.
Even if you didn't comment, this line should be
[cell.picture sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:#"Placeholder.jpg"]];
you have to use
NSURL*url= [[picarray objectAtIndex:indexPath.row]valueForKey:#"img_url"];
[cell.picture setContentMode:UIViewContentModeScaleAspectFill];
[cell.picture sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:#"Placeholder.jpg"]];
instead of
NSURL*url= [[picarray objectAtIndex:indexPath.row]valueForKey:#"img_url"];
[cell.picture setContentMode:UIViewContentModeScaleAspectFill];
[cell.picture sd_setImageWithURL:imageData placeholderImage:[UIImage imageNamed:#"Placeholder.jpg"]];
you have to pass url directly instead of imageData
Try this code :
Add UIActivityIndicatorView in tableview cell.
Changed following code in your cellForRowAtIndexpath.
cell.activityIndicator.center = imageView.center;
cell.activityIndicator.hidesWhenStopped = YES;
NSURL *url= [[picarray objectAtIndex:indexPath.row]valueForKey:#"img_url"];
[cell.picture sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:#"placeholder.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
[cell.activityIndicator stopAnimating];
}];
[cell.picture addSubview:activityIndicator];
[cell.activityIndicator startAnimating];

Asynchronously set images in tableview

I have a TableView using custom cells. I initially was setting grabbing an image from a URL in the cellForRowAtIndexPath method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSDictionary *dictObject = [places objectAtIndex:indexPath.row];
cell.nameLabel.text = [dictObject valueForKey:#"PlaceTitle"];
NSURL *url = [NSURL URLWithString:#"http://images1.fanpop.com/images/image_uploads/Mario-Kart-Wii-Items-mario-kart-1116309_600_600.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
cell.thumbnailImageView.image = image;
return cell;
}
but this was making my TableView scroll laggy. Once I removed the image fetch, it scrolled fine, so I know this is my problem.
My question is: how can I asynchronously fetch this image and set it in my cell? Is there an easy way to do this? Thanks!
Step 1: Have a cache containing images. Either just in memory, better on disk.
Step 2: When you need an image, call a method which either returns an image from the cache, or returns a default image and starts a download.
Step 3: When a download finishes, add the image to the cache. Then find out which rows need the image. Reload all the rows that reload the image.
The download should be done asynchronously using GCD. I would really recommend that you add the download code into a separate, reusable method so that you can handle download errors. Even if you don't do it now, you will do it later.
dataWithContentsOfURL is a synchronous method rather than asynchronous,as
Apple Documents described.
This method is ideal for converting data:// URLs to NSData objects, and can also be used for reading short files synchronously. If you need to read potentially large files, use inputStreamWithURL: to open a stream, then read the file a piece at a time.
In order to asynchronously load image,especially in tableViewCell,try use 3rd part Library SDWebImage
Use this code inside your tableviews cellforindexpath
NSURLRequest *req =[[NSURLRequest alloc]initWithURL:[NSURL URLWithString:#"yourimageurl.com"]];
[NSURLConnection sendAsynchronousRequest:req queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if(!error){
UIImage *image =[UIImage imageWithData:data];
cell.thumbnailImageView.image = image;
}
else{
//error
}
}];
Create UIImageView Class File (i named it to MJTableImageView).
in MJTableImageView.h File
#interface MJTableImageView : UIImageView< NSURLConnectionDelegate, NSURLConnectionDataDelegate >
{
NSMutableData *imageData ;
long long expectedLength;
NSURLConnection *currentConnection;
NSString *File_name;
}
#property(nonatomic,readonly)UIActivityIndicatorView *loadingIndicator;
#property(nonatomic)BOOL showLoadingIndicatorWhileLoading;
-(void)setImageUrl:(NSURL *)imageUrl fileName:(NSString *)name;
#end
in MJTableImageView.m File
-(void)setImageUrl:(NSURL *)imageUrl fileName:(NSString *)name
{
// discard the previous connection
if(currentConnection)
{
[currentConnection cancel];
}
File_name = name;
//reset current image
self.image = nil;
// if(_showLoadingIndicatorWhileLoading)
// {
//show the loading indicator
if(!_loadingIndicator)
{
CGFloat width = self.bounds.size.width*0.5;
_loadingIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake((self.bounds.size.width-width)/2, (self.bounds.size.height-width)/2, 25.0 , 25.0)];
_loadingIndicator.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];
_loadingIndicator.layer.cornerRadius = width*0.1;
}
[self startLoadingIndicator];
// }
// initialize the placeholder data
imageData = [NSMutableData data];
// start the connection
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:imageUrl];
request.cachePolicy = NSURLRequestUseProtocolCachePolicy;
currentConnection = [NSURLConnection connectionWithRequest:request delegate:self];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//if the image view is reused in a table view for example to load another image previous image is discarded
if(connection != currentConnection)
{
[connection cancel];
[self cleanUp];
return;
}
// append new Data
[imageData appendData:data];
// show the partially loaded image
self.image = [UIImage imageWithData:imageData];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
expectedLength = response.expectedContentLength;
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// clean up
[self cleanUp];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// show the full image
self.image = [UIImage imageWithData:imageData];
NSString *filename = [NSHomeDirectory() stringByAppendingFormat:#"/Documents/%#", File_name];
NSData *data = UIImagePNGRepresentation([UIImage imageWithData:imageData]);
[data writeToFile:filename atomically:YES];
// clean up
[self cleanUp];
}
-(void)cleanUp
{
// clean up
imageData = nil;
[self stopLoadingIndicator];
}
-(void)startLoadingIndicator
{
if(!_loadingIndicator.superview)
{
[self addSubview:_loadingIndicator];
}
[_loadingIndicator startAnimating];
}
-(void)stopLoadingIndicator
{
if(_loadingIndicator.superview)
{
[_loadingIndicator removeFromSuperview];
}
[_loadingIndicator stopAnimating];
}
I am using StoryBoard so i add ImageClass(MJTableImageView) file to UItableviewcell ImageView and set tag number to it.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSDictionary *dict = [self.arr objectAtIndex:indexPath.row];
UITableViewCell *cell = [self.MJTableView dequeueReusableCellWithIdentifier:#"MJImageCell"];
if(cell == nil)
{
}
UILabel *appName = (UILabel*)[cell.contentView viewWithTag:2];
appName.text = [dict valueForKey:#"trackName"];
MJTableImageView *imageview = (MJTableImageView *)[cell.contentView viewWithTag:1];
NSString *url = [dict valueForKey:#"artworkUrl60"];
NSString *filename = [NSHomeDirectory() stringByAppendingFormat:#"/Documents/%#",[dict valueForKey:#"trackName"] ];
NSData *data = [NSData dataWithContentsOfFile:filename];
if(data)
{
imageview.image = [UIImage imageWithData:data];
}
else
{
[imageview setImageUrl:[NSURL URLWithString:url] fileName:[dict valueForKey:#"trackName"]];
}
return cell;
}
For More details see Github Project MJTableImageSwift it is in Swift.

Scrolling issue Table View with JSON data

I'm parsing some data from a JSON-file located on my server to my Table View.
When I launch the app the app successfully downloads the data to my table view, but when I begin to scroll, the app crashes.
Here's my code:
#import "FirstViewController.h"
#import "YoutubePost.h"
#import "AFNetworking.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
#synthesize tableView = _tableView, activityIndicatorView = _activityIndicatorView, movies = _movies;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"Videos", #"Videos");
self.tabBarItem.image = [UIImage imageNamed:#"newtab1"];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.navigationController setNavigationBarHidden:YES];
self.tableView.separatorColor = [UIColor clearColor];
// Setting Up Activity Indicator View
self.activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
self.activityIndicatorView.hidesWhenStopped = YES;
self.activityIndicatorView.center = self.view.center;
[self.view addSubview:self.activityIndicatorView];
[self.activityIndicatorView startAnimating];
self.tableView.separatorColor = [UIColor clearColor];
// Initializing Data Source
self.movies = [[NSArray alloc] init];
NSURL *url = [[NSURL alloc] initWithString:#"http://my-website.com/link-to-json.php?name=Name&orderby=published"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
self.movies = JSON;
[self.activityIndicatorView stopAnimating];
[self.tableView reloadData];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
}
// Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (self.movies && self.movies.count) {
return self.movies.count;
} else {
return 0;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 378;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"YoutubePost";
YoutubePost *cell = (YoutubePost *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"YoutubePost" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSDictionary *movie = [self.movies objectAtIndex:indexPath.row];
cell.title.text = [movie objectForKey:#"title"];
NSURL *url = [[NSURL alloc] initWithString:[movie objectForKey:#"link"]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
NSString * storyLink = [[_movies objectAtIndex: storyIndex] objectForKey:#"link"];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:storyLink]];
NSString *formattedJSON = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:[self.tweets objectAtIndex:indexPath.row] options:NSJSONWritingPrettyPrinted error:nil] encoding:NSUTF8StringEncoding];
NSLog(#"tweet:\n%#", formattedJSON);
}
#end
What is wrong? I see that the data successfully downloads to my custom Table View Cell, but every time I try to scroll down the app crashes. Please help me fix this.
Thanks.
Correct this:
// Initializing Data Source
//self.movies = [[NSArray alloc] init];
NSURL *url = [[NSURL alloc] initWithString:#"http://my-website.com/link-to-json.php?name=Name&orderby=published"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
self.movies = [[NSArray alloc] initWithArray:JSON];
[self.activityIndicatorView stopAnimating];
[self.tableView reloadData];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
And in your YouTubePost Nib add Identifier "YouTubePost":
And also in your YouTubePost Nib select your title UILabel and in the inspector change from:
To:
Or Change:
To:
This will do the job.
Change the lines below:
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"YoutubePost" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
Like this:
if (cell == nil)
{
UINib *nib = [UINib nibWithNibName:#"YoutubePost" bundle:nil];
[tableView registerNib:nib forCellReuseIdentifier:#"YoutubePost"];
tableViewCell = [tableView dequeueReusableCellWithIdentifier:#"YoutubePost"];
}
It looks like you're not doing any checking for [NSNull null] in your JSON. It is possible that the following code will give you [NSNull null] instead of an NSDictionary:
NSDictionary *movie = [self.movies objectAtIndex:indexPath.row];
You should filter these out before calling reloadData
Similarly, this line could also potentially return [NSNull null]:
cell.title.text = [movie objectForKey:#"title"];
You need to be prepared to handle that case. This may help you: Replace all NSNull objects in an NSDictionary

Custom UITableViewCell with UIImageView not showing image

I have a custom cell with UIImageView, and it is not showing the image. I have tried setting image to default cell.imageView.image property, and it works just fine, but doesn't work with my custom ImageView.
I load my custom Cell from Xib, and I believe it has to do with lazy loading of UIImageView. How do I make it work?
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCell";
DVGTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.tag = indexPath.row;
if (self.loader.parsedData[indexPath.row] != nil)
{
cell.imageCustom.image = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^(void) {
NSString *url = [self.loader.parsedData[indexPath.row] objectForKey:#"imageLR"];
NSData *imageData = nil;
if ([self.cache objectForKey:url] != nil)
{
imageData = [self.cache objectForKey:url];
}
else
{
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
[self.cache setObject:imageData forKey:[self.loader.parsedData[indexPath.row] objectForKey:#"imageLR"]];
}
dispatch_async(dispatch_get_main_queue(), ^{
if (cell.tag == indexPath.row) {
UIImage *image = [[UIImage alloc] initWithData:imageData];
cell.imageCustom.image = image;
[cell setNeedsLayout];
}
});
});
}
return cell;
}
I usually do Lazy loading for ImageViews with this piece of code, hope it helps:
- (void) loadImageForImageView:(UIImageView *)theImageView WithURL:(NSURL *)url {
NSOperationQueue *queue = [NSOperationQueue new];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:3.0];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *reponse, NSData *data, NSError *error) {
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
theImageView.image = image;
for (UIActivityIndicatorView *spinner in theImageView.subviews) {
[spinner removeFromSuperview];
break;
}
});
}];
}
In your cellForRowAtIndexPath:
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[spinner setColor:[UIColor darkGrayColor]];
spinner.frame = CGRectMake(130 , 53, 20, 20);
[spinner startAnimating];
[imageCell addSubview:spinner];
[self loadImageForImageView:imageCell WithURL:imageURL];
Where imageCell is your UIImageView.

Parsing multiple jSon in IOS

For my code, I am following instruction on this link http://www.youtube.com/watch?v=RJZcD3hfs3k and success,
but I want to modify to multiple JSON and failed (if i print log, that its running).
I modify in:
- (void)viewDidLoad
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
This is my modified code(ViewController.m) :
#import "ViewController.h"
#import "DetailViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"News";
//[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//before
//NSURL *url = [NSURL URLWithString:#"http://zacandcatie.com/YouTube/json.php"];
//after
NSURL *url = [NSURL URLWithString:#"http://service.berisiknews.com/article/byAll/0/3"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
data = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData
{
[data appendData:theData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
//before
//news = [NSJSONSerialization JSONObjectWithData:data options:nil error:nil];
//[mainTableView reloadData];
//ßNSLog(#"array %#", news);
//after
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingMutableContainers error: nil];
NSArray *news = [jsonArray valueForKeyPath:#"data"];
[mainTableView reloadData];
NSLog(#"array %#", news);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"The download could not complete please make sure you're connected to either 3G or Wi-Fi" delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles: nil];
[errorView show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (int)numberINSectionsInTableView: (UITableView *)tableView
{
return 1;
}
- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [news count];
//return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MainCell"];
}
cell.textLabel.text = [[news objectAtIndex:indexPath.row] objectForKey:#"title"];
//cell.detailTextLabel.text = [[news objectAtIndex:indexPath.row] objectForKey:#"date_string"];
cell.detailTextLabel.text = [[news objectAtIndex:indexPath.row] objectForKey:#"category_name"];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
detailViewController.title = [[news objectAtIndex:indexPath.row] objectForKey:#"title"];
detailViewController.newsArticle = [news objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detailViewController animated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Any help?
Your news array is a local variable as your code.
In connectionDidFinishLoading, please modify as below
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingMutableContainers error: nil];
news = [jsonArray valueForKeyPath:#"data"];
[mainTableView reloadData];
NSLog(#"array %#", news);
so it will be the right news array which your are accessing in table view.
it works fine for me.
#interface AlbumViewController ()
#end
#implementation AlbumViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//navigation Controller
[self.navigationController setNavigationBarHidden:NO];
self.title=#"Album List";
//json data parsing
NSURL *url = [NSURL URLWithString:#".......your Link......"];
NSURLRequest *urlrequest = [[NSURLRequest alloc]initWithURL:url];
NSData *data = [NSURLConnection sendSynchronousRequest:urlrequest returningResponse:nil error:nil];
dict_data = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.ary_data = [dict_data objectForKey:#"album"];
NSLog(#"%#",self.ary_data);
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [ary_data count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#""];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
NSMutableDictionary *dic= [[ary_data objectAtIndex:indexPath.row] mutableCopy];
AlbumCellController *albumCell = [[AlbumCellController alloc]init];
[cell.contentView addSubview:albumCell.view];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
albumCell.Img_album.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[dic objectForKey:#"cover_photo"]]]];
});
albumCell.lbl_name.text = [dic objectForKey:#"title"];
albumCell.lbl_releasedate.text = [dic objectForKey:#"release_date"];
NSString *SongNo=[dic objectForKey:#"no_of_songs"];
NSLog(#"%#",SongNo);
//albumCell.lbl_songno.text=SongNo;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableDictionary *dic= [[ary_data objectAtIndex:indexPath.row] mutableCopy];
SongsViewController *songList = [[SongsViewController alloc]init];
songList.imgURL = [dic objectForKey:#"cover_photo"];
songList.Album_id = [dic objectForKey:#"album_id"];
[self.navigationController pushViewController:songList animated:YES];
}

Resources