I am using UITableView to list some images from Internet. So i use AFNetworking's setImageWithURLRequest:placeholderImage:success:failure:methord, when the image is downloaded, i need to do some process then display. In order to refresh the processed image i use
[wTableView beginUpdates];
[wTableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
[wTableView endUpdates];
in the success block. It seems this works when first time loaded, but when i scroll the tableview, the rows are messed up, also one row is disappeared and its easy to crash in the [wTableView endUpdates]; method. what's wrong with this method?
The related code snippet is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *tableIdentifier = #"cell";
CouponTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:tableIdentifier];
if (!cell) {
cell = [[CouponTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableIdentifier];
}
[cell prepareForReuse];
NSArray *coupons = [mCoupons objectAtIndex:indexPath.section];
CouponDB *couponDB = [coupons objectAtIndex:indexPath.row];
NSString *thumbLink;
if (couponDB) {
[cell.textLabel setText:couponDB.couponInfo.company];
[cell.textLabel setFont:[UIFont boldSystemFontOfSize:CELL_LABEL_FONT_SIZE]];
[cell.textLabel setTextColor:[UIColor grayColor]];
[cell.textLabel setBackgroundColor:[UIColor clearColor]];
[cell.detailTextLabel setText:[NSString stringWithFormat:#"Expires:%#",couponDB.couponInfo.deadline]];
[cell.detailTextLabel setBackgroundColor:[UIColor clearColor]];
thumbLink = [self thumbLink:couponDB.couponInfo.imgURL];
[cell setNeedsLayout];
if (couponDB.redeem_status) {
UIImageView * __weak imageView = cell.imageView;
CouponTableController * __weak table = self;
UITableView *__weak wTableView = mTableView;
[cell.imageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:thumbLink]] placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
imageView.image = [table crossedImage:image];
#synchronized(wTableView){
[wTableView beginUpdates];
[wTableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
[wTableView endUpdates];
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"cell imageview load error:%#",error);
}];
} else {
[cell.imageView setImageWithURL:[NSURL URLWithString:thumbLink] placeholderImage:[UIImage imageNamed:#"default_cover.jpg"]];
}
}
if (![cell.backgroundView isKindOfClass:[CouponTableCellBackgroud class]]) {
cell.backgroundView = [[CouponTableCellBackgroud alloc] init];
}
return cell;
}
the first time the table is loaded(no scroll) is like this:
when you scroll down and up the table rows are messed up, which is like below:
Any suggestions are appreciated.
Try this, instead of reloading the cell. Declare a weak pointer to the cell
__weak UITableViewCell *weakCell = cell;
[cell.imageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:thumbLink]] placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakCell.imageView.image = [table crossedImage:image];
[weakCell setNeedsLayout];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"cell imageview load error:%#",error);
}];
Can you try this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"YourResuseIdentifier";
CouponTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:tableIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:SimpleTableIdentifier];
}
else
{
for (UIView *subview in cell.contentView.subviews)
[subview removeFromSuperview];
}
NSArray *coupons = [mCoupons objectAtIndex:indexPath.section];
CouponDB *couponDB = [coupons objectAtIndex:indexPath.row];
NSString *thumbLink;
if (couponDB) {
[cell.textLabel setText:couponDB.couponInfo.company];
[cell.textLabel setFont:[UIFont boldSystemFontOfSize:CELL_LABEL_FONT_SIZE]];
[cell.textLabel setTextColor:[UIColor grayColor]];
[cell.textLabel setBackgroundColor:[UIColor clearColor]];
[cell.detailTextLabel setText:[NSString stringWithFormat:#"Expires:%#",couponDB.couponInfo.deadline]];
[cell.detailTextLabel setBackgroundColor:[UIColor clearColor]];
thumbLink = [self thumbLink:couponDB.couponInfo.imgURL];
if (couponDB.redeem_status) {
UIImageView * __weak imageView = cell.imageView;
CouponTableController * __weak table = self;
UITableView *__weak wTableView = mTableView;
[cell.imageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:thumbLink]] placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
imageView.image = [table crossedImage:image];
[wTableView beginUpdates];
[wTableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
[wTableView endUpdates];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"cell imageview load error:%#",error);
}];
} else {
[cell.imageView setImageWithURL:[NSURL URLWithString:thumbLink] placeholderImage:[UIImage imageNamed:#"default_cover.jpg"]];
}
}
if (![cell.backgroundView isKindOfClass:[CouponTableCellBackgroud class]]) {
cell.backgroundView = [[CouponTableCellBackgroud alloc] init];
}
return cell;
}
I change the load image code to
UIImageView * __weak imageView = cell.imageView;
CouponTableController * __weak table = self;
[cell.imageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:thumbLink]] placeholderImage:[UIImage imageNamed:#"default_cover.jpg"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
imageView.image = [table crossedImage:image];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"cell imageview load error:%#",error);
}];
Only add one placeholder image and remove the tableview updates. then it refresh cells automatically.
Related
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
TVcell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[TVcell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.titleLabel.text = [[[arrayData objectAtIndex:indexPath.row]valueForKey:#"title"]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
cell.txtlabel.text = [[[arrayData objectAtIndex:indexPath.row] valueForKey:#"description"]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
cell.tag = indexPath.row;
cell.imageView.image = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^(void) {
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[enclosureUrlArray objectAtIndex:indexPath.row]]];
UIImage* image = [[UIImage alloc] initWithData:imageData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
if (cell.tag == indexPath.row) {
cell.IMGLabel.image = image;
[cell setNeedsLayout];
}
});
}
});
return cell;
}
while i'm scrolling that same images are appearing on the cells,which cells im reusing.i used scroll view delegate also.im storing urls in enclosureUrlArray and i'm passing.
Put cell.IMGLabel.image = nil in your cellForRowAtIndexPath before downloading image, i.e. below cell.imageView.image = nil; this line.
Or set some place holder image (no image available kind of image to cell's image in interface builder), so if image is not downloaded then it will show this place holder image otherwise it will show downloaded image.
SDWebImage is good for this kind of case. It will cache the images so it will give better performance also. There is nothing wrong to use any good third party library.
By using SDWeb image:
#import <SDWebImage/UIImageView+WebCache.h>
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the new provided sd_setImageWithURL: method to load the web image
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}
You can also use NSURLSession as well,see this link
Async image loading from url inside a UITableView cell - image changes to wrong image while scrolling
NSURL *url = [NSURL URLWithString:[enclosureUrlArray objectAtIndex:indexPath.row]];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (data) {
UIImage *image = [UIImage imageWithData:data];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
MyCell *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath];
if (updateCell)
updateCell.IMGLabel.image = image;
});
}
}
}];
[task resume];
works perfect for me..
with the help of sdwebimage you can show the image like this:-
NSString *string2 = [[businessListArray objectAtIndex:indexPath.row ]valueForKey:#"logo"];
NSURL *url1 = [NSURL URLWithString:
[NSString stringWithFormat:
#"%#%#",
#"http://dev-demo.info.bh-in-15./upload/post/",
string2]];
UIImageView *imageView = (UIImageView *)[cell.contentView viewWithTag:301];
[imageView sd_setImageWithURL:url1
placeholderImage:[UIImage imageNamed:#"pocket.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
imageView.image = image;
}];
I have problem with download image from URL string. When I use this for download image and set in on imageView on view it works but now I have to set it on imageView on Cell.
I cannot put this on cellForRowAtIndexPath: method where I have access to imageView on cell.
__weak EditViewController *weakSelf = self;
[weakSelf.imageView setImageWithURLRequest:request placeholderImage:placeholderImage
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakSelf.imageView.image = image;
[self.tableView reloadData];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
[self prepareAndShowAlertView];
}];
I'll be glad for any help with this. Thanks in advance.
If you are not able to put your download to cellForRow:AtIndexPath: delegate method than you need to add #property (nonatomic, strong) UIImage *image; to your controller and when image is downloaded
...success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakSelf.imageView.image = image;
self.image = image;
[self.tableView reloadData];
}
and in cellForRow:AtIndexPath: setup your image
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
[cell.imageView setImage:self.image];
return cell;
}
I am loading images in UITableViewCell receiving from url using below code, everything is working fine but the image load very slow in UITableViewCell and if i think as a user, it is not acceptable.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [checkData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger i =indexPath.row;
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UIImageView propertyImage = (UIImageView *)[cell viewWithTag:10];
NSString *test = [[checkData objectAtIndex:i]valueForKey:#"image"];
CGRect frame=propertyImage.bounds;
AsyncImageView asyImage=[[AsyncImageView alloc] initWithFrame:frame];
[asyImage setImage:[UIImage imageNamed:#"loading.png"]];
self.urlForTesting=[NSURL URLWithString:test];
[asyImage loadImageFromURL:self.urlForTesting];
asyImage.imageURL =self.urlForTesting;
asyImage.contentMode = UIViewContentModeScaleToFill;
asyImage.layer.masksToBounds=YES;
[propertyImage addSubview:asyImage];
return cell;
}
Use AFNetworking Class & add additional two file to download from github "UIImageView+AFNetworking" and import in your project. then after add this code from "cellForRowAtIndexPath"
// Fetch Image from URL
NSURL *url = [NSURL URLWithString:[[checkData objectAtIndex:i]valueForKey:#"image"]];
[objWinner.actWinner startAnimating];
[objWinner.actWinner setHidden:NO];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[objWinner.imgwinner setImageWithURLRequest:req placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image){
[objWinner.actWinner stopAnimating]; // this is Activityindicator
[objWinner.actWinner setHidden:YES];
objWinner.imgwinner.image = image;
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error){
}];
I may be not understanding the reusing of cells behaviour by the UICollectionView but can someone tell me why two cells are having their properties changed in cellForItemAtIndexPath when it should just be the one cell.
Here's my code.
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotoCollectionViewCell *cell = (PhotoCollectionViewCell *) [collectionView dequeueReusableCellWithReuseIdentifier:#"PhotoCollectionViewCell" forIndexPath:indexPath];
if (![[self.userPhotos objectAtIndex:indexPath.row] isEqualToString:#""]){
NSString *photoUrl = [self.userPhotos objectAtIndex:indexPath.row];
NSURL *imageURL = [NSURL URLWithString: photoUrl];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageURL];
[cell.photoImageView setImageWithURLRequest:imageRequest placeholderImage:[UIImage imageNamed:#"anImage"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
cell.photoImageView.image = image;
cell.photoImageView.frame = CGRectMake(0, 0, 100.0f,100.0f);
cell.photoImageView.contentMode = UIViewContentModeScaleAspectFit;
[cell.deleteImageView setFrame:CGRectMake(-4.0f,-4.0f,28.0f,28.0f)];
cell.deleteImageView.layer.cornerRadius = cell.deleteImageView.frame.size.width / 2;
[cell.deleteImageView setAlpha:0.8f];
cell.deleteImageView.layer.borderWidth = 1.0f;
cell.deleteImageView.layer.borderColor = [UIColor redColor].CGColor;
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"%#",[error localizedDescription]);
}];
}else{
cell.photoImageView.image = [UIImage imageNamed:#"camera"];
cell.photoImageView.layer.borderWidth = 1.0f;
cell.photoImageView.layer.borderColor = [UIColor lightGrayColor].CGColor;
NSLog(#"setting alpha & hiding delete");
cell.photoImageView.alpha = 0.4f;
[cell.deleteImageView setHidden:YES];
}
The code in the else part is being executed on cells 2 and 6 for example when it should just be 6. Although the logging says it's just executed on 6
Any idea where I'm going wrong?
Thanks.
I have 5 types of Custom UITableViewCell . I am having numberofrows also correct. But when it comes to display. The last 2 cells are getting over each other .
This is the method i am using to display the cells for the indexpath row. every if statement is working properly. as i checked with NSlog in it .
if (indexPath.row == 0) {
TaskDetailTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TaskDetail" forIndexPath:indexPath];
[cell.assignTo setText:#" Lalu • Aug 30 , 2014 "];
[cell.taskname setText:task_name];
[cell.comments_countLbl setText:comments_count];
// Configure the cell...
NSLog(#"Cell Type %#",#"Task Detail");
return cell;
}
else if (![comments[indexPath.row] isEqual:[NSNull null]] && ![imagecomments[indexPath.row] isEqual:[NSNull null]]) {
Image_Text_Commet_TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"image_text_comment" forIndexPath:indexPath];
[cell.commentText setText:[comments objectAtIndex:indexPath.row]];
NSString *imageURL = [imagecomments objectAtIndex:indexPath.row];
NSString *convertURltoImage = [NSString stringWithFormat:#"%#%#",#"http://localhost:3001/",imageURL];
NSURL *url = [NSURL URLWithString:convertURltoImage];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
UIImage *placeholderImage = [UIImage imageNamed:#"placeholder"];
__weak Image_Text_Commet_TableViewCell *weakCell = cell;
[cell.imageComment setImageWithURLRequest:request
placeholderImage:placeholderImage
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakCell.imageComment.image = image;
[weakCell setNeedsLayout];
} failure:nil];
NSLog(#"Cell Type %#",#"Image and Text");
return cell;
}
else if (![imagecomments[indexPath.row] isEqual:[NSNull null]] && [comments[indexPath.row] isEqual:[NSNull null]]){
ImageCommentTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ImageComment" forIndexPath:indexPath];
NSString *imageURL = [imagecomments objectAtIndex:indexPath.row];
NSString *convertURltoImage = [NSString stringWithFormat:#"%#%#",#"http://localhost:3001/",imageURL];
NSURL *url = [NSURL URLWithString:convertURltoImage];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
UIImage *placeholderImage = [UIImage imageNamed:#"placeholder1"];
__weak ImageCommentTableViewCell *weakCell = cell;
[cell.imageComment setImageWithURLRequest:request
placeholderImage:placeholderImage
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakCell.imageComment.image = image;
[weakCell setNeedsLayout];
} failure:nil];
NSLog(#"Cell Type %#",#"Image Only");
return cell;
}
else if ([imagecomments[indexPath.row] isEqual:[NSNull null]] && ![comments[indexPath.row] isEqual:[NSNull null]]){
CommentTaskTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"commentText" forIndexPath:indexPath];
[cell.memberComment setText:[comments objectAtIndex:indexPath.row]];
NSLog(#"Cell Type %#",#"Text Only");
return cell;
}
else {
AddCommentTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Addcomment" forIndexPath:indexPath];
NSLog(#"Cell Type %#",#"Add Task Only")![This is the method i am using to display the cells for the indexpath row. every if statement is working properly. as i checked with NSlog in it .][3];
return cell;
}
you need to set the height of cell dynamically that may be the problem
use this method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat rowHeight = [self getRowHeightForRow: indexPath.row];
return rowHeight;
}