I have this very serious problem of scrolling the table.
Initially i used GCD for loading the image in Background and setting on table cell.
but the table was not scrolling smoothly.
So i used SDWebImage for that but then the same thing is happening.
Could anyone let me know the reason for this. Why the table Scrolling is not smooth as expected.
Please let me know your views as my app is waiting its release for the only same purpose.
Code :
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *CellIdentifier = #"Cell";
customCellForExhibitor *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSArray *xibPath = [[NSBundle mainBundle]loadNibNamed:#"customCellForExhibitor" owner:self options:nil];
for (id fileObject in xibPath)
{
cell = (customCellForExhibitor*)fileObject;
}
}
objDataModel = [parserDataContentArray objectAtIndex:indexPath.section];
cell.exhibitorNameLabel.text = [objDataModel exhibitorNameObjectClass];
cell.exhibitorText.text = [objDataModel exhibitorOfferObjectClass];
cell.exhibitorSponsorType.text = [objDataModel exhibitorSponsorTypeObjectClass];
[cell.exhibitorSponsorType setTextAlignment:NSTextAlignmentRight];
// #pragma mark GCD;
//
// NSString *ImageURL = [[parserDataContentArray objectAtIndex:indexPath.section] exhibitorImageObjectClass];
//// NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
//// cell.exhibitorImage.image = [UIImage imageWithData:imageData];
//
// dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// //this will start the image loading in bg
// dispatch_async(concurrentQueue, ^{
// NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
//
// //this will set the image when loading is finished
// dispatch_async(dispatch_get_main_queue(), ^{
//
// cell.exhibitorImage.image = [UIImage imageWithData:imageData];
// [cell setNeedsDisplay];
//
// });
// });
NSString *ImageURL = [[parserDataContentArray objectAtIndex:indexPath.section] exhibitorImageObjectClass];
[cell.exhibitorImage setImageWithURL:[NSURL URLWithString:ImageURL]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
if ([cell.exhibitorSponsorType.text isEqualToString:#"Gold"]) {
cell.exhibitorSponsorType.textColor = [UIColor colorWithRed:255/255.0 green:215/255.0 blue:0 alpha:1];
}
else if ([cell.exhibitorSponsorType.text isEqualToString:#"Silver"]){
cell.exhibitorSponsorType.textColor = [UIColor colorWithRed:192/255.0 green:192/255.0 blue:192/255.0 alpha:1];
}
else cell.exhibitorSponsorType.textColor = [UIColor colorWithRed:229/255.0 green:228/255.0 blue:226/255.0 alpha:1];
return cell;
}
Thank You
Best Regards.
Use lazy loading file instead here is the reference u can find it here along with demo how it is implemented.
https://stackoverflow.com/a/18032907/1305001
[cell addSubview:[self addViewWithURL:ImageURL NFrame:CGRectMake(0, 0, 50, 50)]];
add this method below cellForRow
-(UIView*)addViewWithURL:(NSString*)urlStr NFrame:(CGRect)rect
{
LazyLoad *lazyLoading;
lazyLoading = [[LazyLoad alloc] init];
[lazyLoading setBackgroundColor:[UIColor grayColor]];
[lazyLoading setFrame:rect];
[lazyLoading loadImageFromURL:[NSURL URLWithString:urlStr]];
return lazyLoading;
}
Set placeholder in LazyLoad.m file's init method as
-(id)init{
if (self==[super init]) {
[self setImage:[UIImage imageNamed:#"placeholder.png"]];
}
return self;
}
And change superClass of LazyLoad.h file to UIImageView from UIView as
#interface LazyLoad : UIImageView
Related
Im using the following code to load images from url into collection view
-
(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"Cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
UILabel *recipeLabel = (UILabel *)[cell viewWithTag:200];
if ([ImageArray count] >0){
for(int i = 0; i < [ImageArray count]; i++)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
NSData *data0 = [NSData dataWithContentsOfURL: [NSURL URLWithString:[ImageArray objectAtIndex:indexPath.row]]];
UIImage *image = [UIImage imageWithData: data0];
dispatch_sync(dispatch_get_main_queue(), ^(void) {
recipeImageView.image = image;
});
});
}
}else{
UILabel *title = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, cell.bounds.size.width, 40)];
title.text = #"No image record found";
title.tag = 200;
[title setHidden:true];
[cell.contentView addSubview:title];
}
[spinnerShow stopAnimating];
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
return cell;
}
If the ImageArray has got some url, if loop will be executed. Else the else loop will be executed where it will display a label saying no image record found. But the uilabel is not getting visible
Why are you using for loop in cellForItemAtIndexPath? This method is called for every item in UICollectionView. In else condition, add log or breakpoint and check if it is going there or always going in if condition. Make sure if you need to check for array count or want to check if image exists on URL?
I am using this to display some labels and images by JSON parsing in to tableView but images are not coming at the first launch when scrolling the tableview images are coming and dancing i mean not coming in order format help me with this
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
self.customCellClass = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (self.customCellClass == nil)
{
self.customCellClass = [[CellCustom alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
self.customCellClass.nameLabel.text = [[arrayData objectAtIndex:indexPath.row] objectForKey:#"name"]; // label
self.customCellClass.cityLabel.text = [[arrayData objectAtIndex:indexPath.row] objectForKey:#"region"]; // label
NSString * stripped = [[[arrayData objectAtIndex:indexPath.row] objectForKey:#"summary"] stripHtml]; //label
self.customCellClass.detailLabel.text = stripped;
self.customCellClass.mainImage.image = nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
NSData *data0 = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[[arrayData objectAtIndex:indexPath.row]objectForKey:#"images"]objectForKey:#"logo"]]];
UIImage *image = [UIImage imageWithData:data0];
dispatch_sync(dispatch_get_main_queue(), ^(void) {
self.customCellClass.mainImage.image = image;
});
});
return self.customCellClass;
}
Replace below code in UITableView's cellForRowAtIndexPath method :
//Check if cell has image or not
if(!self.customCellClass.mainImage.image)
{
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(q, ^{
NSData *data0 = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[[arrayData objectAtIndex:indexPath.row]objectForKey:#"images"]objectForKey:#"logo"]]];
UIImage *image = [UIImage imageWithData:data0];
//Get main queue
dispatch_async(dispatch_get_main_queue(), ^{
/* This is the main thread again, where we set the tableView's image to be what we just fetched. */
self.customCellClass.mainImage.image = image;
});
});
}
Good solution is if you are using AFNetworking then use UIImageView+AFNetworking category
NSURL *imageURL = [NSURL URLWithString:[[[arrayData objectAtIndex:indexPath.row]objectForKey:#"images"]objectForKey:#"logo"]]
[self.customCellClass.mainImage setImageWithURL:imageURL placeholderImage:nil];
You are assigning image=nil every time when cell is loading and downloading the same image.
You can user following class to do this seamlessly.
AsyncImageView.h
#import <UIKit/UIKit.h>
#interface AsyncImageView : UIView {
NSURLConnection *connection;
NSMutableData *data;
NSString *urlString; // key for image cache dictionary
}
-(void)loadImageFromURL:(NSURL*)url;
-(void)loadBackgroundImage:(UIImage *)image;
-(UIImage*)loadImageFromURLForGetIamge:(NSURL*)url;
-(BOOL)getCachedImageWithUrl:(NSString*)url;
#end
and AsyncImageView.m
#import "AsyncImageView.h"
#import "ImageCacheObject.h"
#import "ImageCache.h"
//
// Key's are URL strings.
// Value's are ImageCacheObject's
//
static ImageCache *imageCache = nil;
#define SPINNY_TAG 5555
#implementation AsyncImageView
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
}
- (void)dealloc {
[connection cancel];
}
-(void)loadBackgroundImage:(UIImage *)image
{
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.layer.masksToBounds=YES;
//imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout];
[self setNeedsLayout];
imageView=nil;
}
-(void)loadImageFromURL:(NSURL*)url
{
if (connection != nil) {
[connection cancel];
connection = nil;
}
if (data != nil) {
data = nil;
}
if (imageCache == nil) // lazily create image cache
imageCache = [[ImageCache alloc] initWithMaxSize:2*1024*1024]; // 2 MB Image cache
// NSLog(#"Value of the url here = %#",url);
urlString = [[url absoluteString] copy];
UIImage *cachedImage = [imageCache imageForKey:urlString];
if (cachedImage != nil)
{
if ([[self subviews] count] > 0)
{
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:cachedImage];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.layer.masksToBounds=YES;
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout]; // is this necessary if superview gets setNeedsLayout?
[self setNeedsLayout];
imageView=nil;
return;
}
UIActivityIndicatorView *spinny = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinny.tag = SPINNY_TAG;
spinny.frame=CGRectMake(self.frame.size.width/2-10, self.frame.size.height/2-10, 20, 20);
spinny.center = self.center;
[spinny startAnimating];
[self addSubview:spinny];
[self bringSubviewToFront:spinny];
spinny=nil;
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
-(BOOL)getCachedImageWithUrl:(NSString*)url
{
BOOL isIamgeCached=NO;
if (imageCache == nil)
imageCache = [[ImageCache alloc] initWithMaxSize:2*1024*1024]; // 2 MB Image cache
UIImage *cachedImage = [imageCache imageForKey:url];
if (cachedImage != nil)
{
isIamgeCached=YES;
}
return isIamgeCached;
}
-(UIImage*)loadImageFromURLForGetIamge:(NSURL*)url
{
if (connection != nil)
{
[connection cancel];
connection = nil;
}
if (data != nil)
{
data = nil;
}
if (imageCache == nil) // lazily create image cache
imageCache = [[ImageCache alloc] initWithMaxSize:2*1024*1024]; // 2 MB Image cache
// NSLog(#"Value of the url here = %#",url);
urlString = [[url absoluteString] copy];
UIImage *cachedImage = [imageCache imageForKey:urlString];
if (cachedImage != nil)
{
if ([[self subviews] count] > 0)
{
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:cachedImage];
imageView.contentMode = UIViewContentModeScaleToFill;
imageView.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout]; // is this necessary if superview gets setNeedsLayout?
[self setNeedsLayout];
imageView=nil;
return cachedImage;
}
UIActivityIndicatorView *spinny = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinny.tag = SPINNY_TAG;
spinny.frame=CGRectMake(self.frame.size.width/2-10, self.frame.size.height/2-10, 20, 20);
//spinny.center = self.center;
[spinny startAnimating];
[self addSubview:spinny];
[self bringSubviewToFront:spinny];
spinny=nil;
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:20.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
return cachedImage;
}
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)incrementalData {
if (data==nil)
{
data = [[NSMutableData alloc] initWithCapacity:2048];
}
[data appendData:incrementalData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection
{
connection = nil;
UIView *spinny = [self viewWithTag:SPINNY_TAG];
[spinny removeFromSuperview];
if ([[self subviews] count] > 0)
{
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImage *image = [UIImage imageWithData:data];
[imageCache insertImage:image withSize:[data length] forKey:urlString];
UIImageView *imageView = [[UIImageView alloc]
initWithImage:image];
imageView.contentMode = UIViewContentModeScaleToFill;
imageView.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout]; // is this necessary if superview gets setNeedsLayout?
[self setNeedsLayout];
imageView=nil;
data = nil;
}
#end
You use dispatch_async to load image from remote, that means the images to be displayed in tableview cells are loaded asynchronously. And you use a instance variable to record current cell, which cause the problem you met.
After a image being loaded finished (may take few minutes), it want to be displayed in a cell (written in this code),
dispatch_sync(dispatch_get_main_queue(), ^(void) {
self.customCellClass.mainImage.image = image;
});
only to find that the self.customCellClass points to a wrong cell (the - (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath was called several times during the image being loaded, and each calling changes the pointing of self.customCellClass to other cell).
So, the order of images is wrong.
Try this:
Use a locality variable to keep the cell get from dequeueReusableCellWithIdentifier. Like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
CellCustom *customCellClass = (CellCustom *)[tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (customCellClass == nil)
{
customCellClass = [[CellCustom alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
customCellClass.nameLabel.text = [[arrayData objectAtIndex:indexPath.row] objectForKey:#"name"]; // label
customCellClass.cityLabel.text = [[arrayData objectAtIndex:indexPath.row] objectForKey:#"region"]; // label
NSString * stripped = [[[arrayData objectAtIndex:indexPath.row] objectForKey:#"summary"] stripHtml]; //label
customCellClass.detailLabel.text = stripped;
customCellClass.mainImage.image = nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
NSData *data0 = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[[arrayData objectAtIndex:indexPath.row]objectForKey:#"images"]objectForKey:#"logo"]]];
UIImage *image = [UIImage imageWithData:data0];
dispatch_sync(dispatch_get_main_queue(), ^(void) {
customCellClass.mainImage.image = image;
});
});
return customCellClass;
}
Besides, take a look at the difference between - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier and - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath.
I am making an app in which i am getting data from server and in data image path is also coming but when i am setting image to my tableview cell app will become too much heavy may b i am not setting image properly below is my sample code thanx in advance :)
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *tableviewidentifier = #"cell";
tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1){
// [[cell textLabel] setText:#"Load more records"];
}
UILabel *valuedate = (UILabel *)[cell viewWithTag:21];
UILabel *msg = (UILabel *)[cell viewWithTag:22];
UILabel *date = (UILabel *)[cell viewWithTag:23];
UILabel *time = (UILabel *)[cell viewWithTag:24];
valuedate.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
msg.text=#"How are you?";
NSString *img=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerPhoto"];// here i am getting image path
UIImage *img1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:img]]];
cell.imageView.image=img1;// here i am setting image due to which app is so heavy and stuck
return cell;
}
Dont use imageWithData: for setting images. It is synchronous and will make your app run slow.
Instead of that Use SDWebImage
You just need to do following things:
Dump SDWebImage folder into your project.
Import UIImageView+WebCache.h.
Set the image using: sd_setImageWithURL:
OR
by GCD (Grand Central Dispatch) and sending asynchronous requests. Code copied from HERE.
First implement following method.
- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if ( !error )
{
UIImage *image = [[UIImage alloc] initWithData:data];
completionBlock(YES,image);
} else{
completionBlock(NO,nil);
}
}];
}
and then in your cellForRowAtIndexPath
[self downloadImageWithURL:your_url completionBlock:^(BOOL succeeded, UIImage *image) {
if (succeeded) {
// change the image in the cell
cell.imageView.image = image;
}
}];
try this below code, hope this helps u .
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}
if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1)
{
// [[cell textLabel] setText:#"Load more records"];
}
UILabel *valuedate = (UILabel *)[cell viewWithTag:21];
UILabel *msg = (UILabel *)[cell viewWithTag:22];
UILabel *date = (UILabel *)[cell viewWithTag:23];
UILabel *time = (UILabel *)[cell viewWithTag:24];
valuedate.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
msg.text=#"How are you?";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString *img=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerPhoto"];// here i am getting image path
NSURL *url = [NSURL URLWithString:img];
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_sync(dispatch_get_main_queue(), ^{ //in main thread update the image
cell.imageView.image = image;
cell.textLabel.text = #""; //add this update will reflect the changes
});
});
return cell;
}
EDIT
in order to reuse the downloaded image u can either save them on disk or just for save them some where for example in dictionary for temporary using
in below code i took one example dictionary, and strong the download images with row as key
#interface ViewController ()
{
NSMutableDictionary *imagesDictionary; //lets declare a mutable dictionary to hold images
}
in this method just initialise it
- (void)viewDidLoad {
[super viewDidLoad];
// rest of your code
//...........
//
imagesDictionary = [[NSMutableDictionary alloc]init]; //initilise
}
in index this method just add the downloaded images to dictionary for corresponding row as key
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}
if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1)
{
// [[cell textLabel] setText:#"Load more records"];
}
__block NSString *row = [NSString stringWithFormat:#"%d",indexPath.row]; //add this
UILabel *valuedate = (UILabel *)[cell viewWithTag:21];
UILabel *msg = (UILabel *)[cell viewWithTag:22];
UILabel *date = (UILabel *)[cell viewWithTag:23];
UILabel *time = (UILabel *)[cell viewWithTag:24];
// valuedate.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
msg.text=#"How are you?";
if(![[imagesDictionary allKeys] containsObject:row]) //if image not found download and add it to dictionary
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// NSString *img=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerPhoto"];// here i am getting image path
NSURL *url = [NSURL URLWithString:img];
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_sync(dispatch_get_main_queue(), ^{ //in main thread update the image
[imagesDictionary setObject:image forKey:row]; //sorry, while editing to your code i forgot to add this
cell.imageView.image = image;
cell.textLabel.text = #""; //add this update will reflect the changes
NSLog(#"loading and addig to dictionary");
});
});
}
else
{
cell.imageView.image = [imagesDictionary objectForKey:row];
NSLog(#"retriving from dictioary");
}
return cell;
}
First of all you are calling dataWithContentsOfURL: function which will make the app non responsive because you are calling it on main thread. To make it responsive you need to create a custom cell YourCell and declare a method in YourCell.h
#interface YourCell : UITableViewCell
{
UIImage *_cImage;
}
- (void)downloadImageFromURL:(NSURL *)imageUrl;
#end
Now in YourCell.m you need to do like this:
- (void)downloadImageFromURL:(NSURL *)imageUrl
{
if (_cImage != nil)
{
self.imageView.image = _cImage;
}
else
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
_cImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageUrl]];
dispatch_sync(dispatch_get_main_queue(), ^{
self.imageView.image = _cImage;
});
});
}
}
Now from cellForRowAtIndexPath: you just need to call downloadImageFromURL: function of YourCell and pass the imageUrl to it and its the cell responsibility to download and show the image.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier= #"YourCell";
YourCell *cell = (YourCell *)[self.activitiesTableView_ dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[NSBundle mainBundle] loadNibNamed:#"YourCell" owner:self options:nil] objectAtIndex:0];
}
// Set your UILabels as before.....
NSString *imagePath=[[self.inboxmessagesarray objectAtIndex:indexPath.row] objectForKey:#"offerPhoto"];
[cell downloadImageFromURL:[NSURL URLWithString:imagePath]];
return cell;
}
Let me know if you have any questions.
UIImageView *img1 = (UIImageView *)[cell viewWithTag:104];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
img1.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:img]]];
});
});
Send async requests for images. Doing this would not block your UI until the image gets loaded.
I'm trying to show a button on certain cells in my tableview depending on type of image showing in that cell
soo i have two NSMutableArray's one holding the thumbnail image URL's and the other NSMutableArray holding the type of the url if it was image or video
the problem is the button doesn't show on all the video type cells
here is my code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TVCustomCell";
TVCustom *cell = (TVCustom *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"TVCustom" owner:self options:nil];
for (id currentObject in topLevelObjects) {
if ([currentObject isKindOfClass:[TVCustom class]]) {
cell = (TVCustom *) currentObject;
break;
}
}
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *imgURL = [arrayImagesURL objectAtIndex:indexPath.row];
NSURL *imageURL = [NSURL URLWithString:imgURL];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:imageData];
cell.thumbImg.image = image;
});
});
NSString *MediaType = [NSString stringWithFormat:#"%#", [arrayType objectAtIndex:indexPath.row]];
if ([MediaType isEqualToString:#"video"]) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(120, 319, 50, 30);
[button setTitle:#"Play" forState:UIControlStateNormal];
button.tag = indexPath.row;
[button addTarget:self action:#selector(PlayBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor= [UIColor clearColor];
[cell.contentView addSubview:button];
}
return cell;
}
i don't know what i'm doing wrong, any idea ?
I see different problems here.
First
Your code creates new buttons every time the user scrolls in the tableView. This is because you use dequeueReusableCellWithIdentifier which is great and returns existing cells instead of creating new ones.
But then you add a new button on cells which already exist (and may or may not have a button)
[cell.contentView addSubview:button];
I suggest you add the button in your TVCustom class:
In the TVCustom.h
#property (strong, nonatomic) UIButton *viedoButton;
In TVCustom.m
- (UIButton *)videoButton
{
if (!_videoButton) {
_videoButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
_videoButton.frame = CGRectMake(120, 319, 50, 30);
[_videoButton setTitle:#"Play" forState:UIControlStateNormal];
[_videoButton addTarget:self action:#selector(PlayBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
_videoButton.backgroundColor= [UIColor clearColor];
[self.contentView _videoButton];
}
return _videoButton;
}
Then in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath you only do :
if ([MediaType isEqualToString:#"video"]) {
cell.videoButton.hidden = NO;
} else {
cell.videoButton.hidden = YES;
}
This way every cell will have only one button and it will be visible only when you need it but not re-allocated every time. But PlayBtnClicked will have to be in your TVCustom class and call your viewController through a delegate.
Second
You should not handle the loading of your image in the cellForRowAtIndexPath method. Encapsulate it your TVCustom class:
In TVCustom.h
#property (strong, nonatomic) NSString *imgURL;
In TVCustom.m
- (void)setImgURL:(NSString *)imgURL
{
_imgURL = imgURL;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString:imgURL];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:imageData];
self.thumbImg.image = image;
});
});
}
Then in cellForRowAtIndexPath it will look like :
cell.imgURL = [arrayImagesURL objectAtIndex:indexPath.row];
Third
I do not know if you have any particular reason for this:
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"TVCustom" owner:self options:nil];
for (id currentObject in topLevelObjects) {
if ([currentObject isKindOfClass:[TVCustom class]]) {
cell = (TVCustom *) currentObject;
break;
}
}
}
But a good way to do this is in your viewController's viewDidLoad (or other method):
NSString *identifier = #"TVCustomCell";
NSString *nibName = #"TVCustom";
UINib *cellNib = [UINib nibWithName:nibName];
[self.tableView registerNib:cellNib forCellReuseIdentifier:identifier];
Your final code should look like :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TVCustomCell";
TVCustom *cell = (TVCustom *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.imgURL = [arrayImagesURL objectAtIndex:indexPath.row];
if ([MediaType isEqualToString:#"video"]) {
cell.videoButton.hidden = NO;
} else {
cell.videoButton.hidden = YES;
}
return cell;
}
I have a tableview in which i load some cells, and insert some images in. The images is downloaded with the help of SDWebImage library. There is one problem though: It seems the function to download the image is never called (or abruptet before completion), and therefore the complete method is never called on the imageView iv. It just inserts the placeholder image instead, which is a transparent png (yeah, i checked, it is there ^^).
No error is NSLogged in the if statement either.
Any ideas?
code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *myIdentifier = #"defaultcell";
UIActivityIndicatorView *spinner;
UIImageView *iv;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:myIdentifier forIndexPath:indexPath];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:myIdentifier];
//build spinner
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(160, 47);
spinner.tag = 101;
[cell.contentView addSubview:spinner];
//build ImageView
iv = [[UIImageView alloc] initWithFrame:(CGRect){.size={80, 60}}];
iv.contentMode = UIViewContentModeScaleAspectFill;
iv.clipsToBounds = YES;
iv.tag = 102;
iv.frame = CGRectMake(15, 17, 80, 60);
[cell.contentView addSubview:iv];
} else {
spinner = (UIActivityIndicatorView*)[cell viewWithTag:101];
iv = (UIImageView*)[cell viewWithTag:102];
}
[spinner startAnimating];
//the rest goes here
cell.textLabel.hidden = YES;
cell.detailTextLabel.hidden = YES;
cell.imageView.hidden = YES;
NSString *profilePicName = [NSString stringWithFormat:#"%#%#", [self.dbhandler getPicturesPath], [[gallery objectAtIndex:indexPath.row] valueForKey: #"filename"]];
NSLog(#"%#", profilePicName);
[iv setImageWithURL:[NSURL URLWithString:profilePicName] placeholderImage:[UIImage imageNamed:#"placeholder.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType){
if(error){
NSLog(#"Callback Error: %#", error);
}
[spinner stopAnimating];
cell.textLabel.hidden = NO;
cell.detailTextLabel.hidden = NO;
cell.imageView.hidden = NO;
NSLog(#"done");
}];
NSString *subtitle = [NSString stringWithFormat:#"Comments: %# \nPosted: %#", [[gallery objectAtIndex:indexPath.row] valueForKey:#"comments"], [[gallery objectAtIndex:indexPath.row] valueForKey:#"created_at"]];
cell.detailTextLabel.numberOfLines = 0;
cell.textLabel.text = [NSString stringWithFormat:#"Votes: %#",[[gallery objectAtIndex:indexPath.row] valueForKey:#"votes"]];
cell.detailTextLabel.text = subtitle;
return cell;
}