UITableView crashes on scroll (memory warnings) - ios

I have made my first UITableView, but when the number of cells is higher than what can be shown on the screen, and I scroll, it then crashes because of lack of memory.
I implemented the SDWEBIMAGE library to load the pictures async. and cache the images afterwards.
If more code is needed, please let me know !
I am a complete newbie at this, so please be gentle :)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *myIdentifier = #"defaultcell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:myIdentifier forIndexPath:indexPath];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:myIdentifier];
}
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(160, 47);
[spinner startAnimating];
[cell.contentView addSubview:spinner];
//hide labels until done loading
cell.textLabel.hidden = YES;
cell.detailTextLabel.hidden = YES;
cell.imageView.hidden = YES;
UIImageView *iv = [[UIImageView alloc] initWithFrame:(CGRect){.size={80, 60}}];
iv.contentMode = UIViewContentModeScaleAspectFill;
iv.clipsToBounds = YES;
iv.frame = CGRectMake(15, 17, 80, 60);
NSString *profilePicName = [NSString stringWithFormat:#"%#%#", [self.dbhandler getPicturesPath], [[gallery objectAtIndex:indexPath.row] valueForKey: #"filename"]];
[iv setImageWithURL:[NSURL URLWithString:profilePicName] placeholderImage:[UIImage imageNamed:#"placeholder.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType){
[spinner stopAnimating];
cell.textLabel.hidden = NO;
cell.detailTextLabel.hidden = NO;
cell.imageView.hidden = NO;
[cell.contentView addSubview:iv];
}];
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;
}
UPDATED FUNCTION:
- (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){
[spinner stopAnimating];
cell.textLabel.hidden = NO;
cell.detailTextLabel.hidden = NO;
cell.imageView.hidden = NO;
NSLog(#"done");
[cell.contentView addSubview:(UIImageView *)[cell viewWithTag:102]];
}];
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;
}

Every-time you reuse a cell you are adding the UIActivityIndicatorView/spinner and UIImageView/iv as subviews. Better approach is to use a custom Prototype cell in the storyboard or reuse existing views by setting a Tag.
UIActivityIndicatorView *spinner;
UIImageView *iv;
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.contentView viewWithTag:101];
iv = (UIImageView*)[cell.contentView viewWithTag:102];
}
[spinner startAnimating];
//the rest goes here
You need to remove other addSubView calls(specifically in the callback block).
This should help you to get started.

Related

how to show messages and image in uitableviewcell in iOS

I am working on chat application. Actually i have 3 arrays. First array stores user name and second array stores chat message and third array stores images. I am picking image from photo gallery.
When user sends any message to the chat wall I display message in bubble.
So I'm writing some conditions like the below:
if arr2 value is not null then displaying chat message
if arr3 value is not null displaying image in chat bubble
if arr2 value is null then i want to hide lbldesc and show only imv gallery image
if arr3 value is null then hide imv gallery image and enable lblDesc
But i got exception like this:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** NSAllocateMemoryPages(4294967295) failed'`
Here is my code:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.selectionStyle=UITableViewCellSelectionStyleNone;
if (itemsDataArr.count>0) {
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(35, 3, 250, 80)];
imgView.image = [UIImage imageNamed:#"speech-bubble-2-hi.png"];
imgView.layer.borderColor = [UIColor clearColor].CGColor;
imgView.tag = 5;
[cell.contentView addSubview:imgView];
NSArray *arr1=[[NSArray alloc]init];
arr1=[itemsUserNameArr objectAtIndex:indexPath.row];
NSString *strval=[arr1 objectAtIndex:0];
lblTitle=[[UILabel alloc]initWithFrame:CGRectMake(50, 5, 150, 20)];
lblTitle.highlightedTextColor=[UIColor whiteColor];
[cell.contentView addSubview:lblTitle];
[lblTitle setFont:[UIFont boldSystemFontOfSize:14]];
lblTitle.text=strval;
[imgView addSubview:lblTitle];
NSArray *arr2=[[NSArray alloc]init];
arr2=[itemsDataArr objectAtIndex:indexPath.row];
NSArray *arr3=[[NSArray alloc]init];
arr3=[itemImgArray objectAtIndex:indexPath.row];
if(![arr2 isEqual:#""])
{
NSString *strmsg=[arr2 objectAtIndex:0];
lblDesc=[[UILabel alloc]initWithFrame:CGRectMake(50, 22, 300, 20)];
lblDesc.highlightedTextColor=[UIColor whiteColor];
lblDesc.font=[UIFont systemFontOfSize:12.0];
[cell.contentView addSubview:lblDesc];
[lblDesc setHidden:NO];
lblDesc.text=strmsg;
[imgView addSubview:lblDesc];
// imv.hidden=YES;
// [imv setHidden:true];
}
arr3=[itemImgArray objectAtIndex:indexPath.row];
if(![arr3 isEqual:nil])
{
NSString *strImg=[arr3 objectAtIndex:0];
NSData *data = [[NSData alloc] initWithData:[NSData dataFromBase64String:strImg]];
//Now data is decoded. You can convert them to UIImage
imv = [[UIImageView alloc]initWithFrame:CGRectMake(93,12, 50, 50)];
imv.image=[UIImage imageWithData:data];
[imgView addSubview:imv];
[lblDesc setHidden:YES];
// lblDesc.hidden=YES;
}
}
return cell;
}
I've used PTSMessagingCell from here:
I've used messages array for texts/images. This is a ruf sample that may help you.
#import "ViewController.h"
#import "PTSMessagingCell.h"
#interface ViewController ()
{
NSMutableArray *messages;
UITextView *sendMsg;
UITableView *chatTable;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
messages = [[NSMutableArray alloc] initWithObjects:#"Hello",[UIImage imageNamed:#"download.jpeg"],#"Check This Out", nil];
chatTable = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-100)];
chatTable.delegate = self;
chatTable.dataSource = self;
chatTable.separatorColor = [UIColor clearColor];
[self.view addSubview:chatTable];
chatTable.backgroundColor = [UIColor clearColor];
sendMsg = [[UITextView alloc]initWithFrame:CGRectMake(0, chatTable.frame.size.height, self.view.frame.size.width-100, 100)];
sendMsg.textColor = [UIColor blackColor];
sendMsg.delegate = self;
sendMsg.backgroundColor = [UIColor whiteColor];
sendMsg.layer.cornerRadius = 3.0f;
[self.view addSubview:sendMsg];
UIButton *sendMsgbtn = [[UIButton alloc]initWithFrame:CGRectMake(sendMsg.frame.size.width, chatTable.frame.size.height, 100, 100)];
[sendMsgbtn setTitle:#"SEND" forState:UIControlStateNormal];
sendMsgbtn.backgroundColor = [UIColor redColor];
[sendMsgbtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[sendMsgbtn addTarget:self action:#selector(sendClicked) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:sendMsgbtn];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapReceived:)];
[tapGestureRecognizer setDelegate:self];
[chatTable addGestureRecognizer:tapGestureRecognizer];
}
-(void)sendClicked{
[sendMsg resignFirstResponder];
[chatTable reloadData];
}
#pragma mark - TableView Delegate and DataSource Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [messages count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
/*This method sets up the table-view.*/
static NSString* cellIdentifier = #"messagingCell";
PTSMessagingCell * cell = (PTSMessagingCell*) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[PTSMessagingCell alloc] initMessagingCellWithReuseIdentifier:cellIdentifier];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[messages objectAtIndex:indexPath.row] isKindOfClass:[UIImage class]]) {
return [(UIImage *)[messages objectAtIndex:indexPath.row] size].height;
}
else{
const char *jsonString = [[NSString stringWithFormat:#"%#",[messages objectAtIndex:indexPath.row]] UTF8String];
NSData *jsonData = [NSData dataWithBytes:jsonString length:strlen(jsonString)];
NSString *goodMsg = [[NSString alloc] initWithData:jsonData encoding:NSNonLossyASCIIStringEncoding];
CGSize messageSize = [PTSMessagingCell messageSize:goodMsg];
NSLog(#"%f",messageSize.height + 2*[PTSMessagingCell textMarginVertical] + 40.0f);
return messageSize.height + 2*[PTSMessagingCell textMarginVertical] + 40.0f;
}
}
-(void)configureCell:(id)cell atIndexPath:(NSIndexPath *)indexPath {
if (messages.count>0) {
PTSMessagingCell* ccell = (PTSMessagingCell*)cell;
if ([[messages objectAtIndex:indexPath.row] isKindOfClass:[UIImage class]]) {
ccell.sent = YES;
ccell.avatarImageView.image = [UIImage imageNamed:[messages objectAtIndex:indexPath.row]];
ccell.messageLabel.text = #"";
}
else{
ccell.sent = YES;
const char *jsonString = [[NSString stringWithFormat:#"%#",[messages objectAtIndex:indexPath.row]] UTF8String];
NSData *jsonData = [NSData dataWithBytes:jsonString length:strlen(jsonString)];
NSString *goodMsg = [[NSString alloc] initWithData:jsonData encoding:NSNonLossyASCIIStringEncoding];
ccell.messageLabel.text = [messages objectAtIndex:indexPath.row];
}
ccell.timeLabel.text = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterFullStyle];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapReceived:)];
[tapGestureRecognizer setDelegate:self];
[ccell addGestureRecognizer:tapGestureRecognizer];
}
}
-(void)tapReceived:(UITapGestureRecognizer *)tapGestureRecognizer
{
// do something, like dismiss your view controller, picker, etc., etc.
[sendMsg resignFirstResponder];
}
Hope this helps.
Create a custom cell and load images in background thread will give better UI performance

SDWebimage setImageWithUrl doesn't complete

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;
}

Lagging local image loading in UItableview

I made an app which load images from photo library or image taken from camera into a table view , but UI freezes every time i scroll up/down or new image added. Here is how i am making the cell for table view .
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath(NSIndexPath*)indexPath {
static NSString *CellIdentifier = #"Cell";
*cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.imageView.frame = CGRectMake(0, 0, 110, 70);
}
NSError *attributesError = nil; NSString *workSpacePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:[images objectAtIndex:indexPath.row]];
NSDictionary *fileAttributes = [[NSFileManager defaultManager]attributesOfItemAtPath:workSpacePath error:&attributesError];
NSNumber * fileSizeNumber = [fileAttributes objectForKey:NSFileSize];
long long int fileKBSize = [fileSizeNumber longLongValue]/1024;
if (fileKBSize > 1024)
{
cell.textLabel.text = [NSString stringWithFormat:#"File name #%i (%lli MB)",indexPath.row + 1,fileKBSize / 1024];
}
else
{
cell.textLabel.text = [NSString stringWithFormat:#"File name #%i (%lli KB)",indexPath.row + 1,fileKBSize];
}
cell.textLabel.backgroundColor = [UIColor clearColor]; NSString *descriptionString = [images objectAtIndex:indexPath.row];
NSLog(#"descriptionString :%#",descriptionString);
if ([[despDectionary objectForKey:descriptionString] length] > 0)
{
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#",[despDectionary objectForKey:descriptionString]];
}
else
{
cell.detailTextLabel.text = #"File Description";
}
dispatch_queue_t bg = dispatch_queue_create("Back Ground", NULL);
dispatch_async(bg,^(void)
{
UIImage *image=[UIImage imageWithData:[NSData dataWithContentsOfFile:workSpacePath]];
dispatch_async(dispatch_get_main_queue(), ^{
//cell.imageView.frame = CGRectMake(0, 0, 110, 70); cell.imageView.image = image;
});
});
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(250, 0, 49,56);
[button setImage:[UIImage imageNamed:#"deletButotn.png"] forState:UIControlStateNormal];
button.tag = indexPath.row;
[button addTarget:self action:#selector(deleteButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button];
return cell;
}
Can somebody please suggest me any solution?

We using this Asyncimageview classes to get image from web serves and showing in UItableview but is not working?

//UITableView
NSString *data_image;
data_image = [[message_array objectAtIndex:indexPath.row] valueForKey:#"img_thumb"];
NSLog(#"data_image---%#",data_image);
if (![data_image isEqualToString:#""])
{
img_bubble = [[UIImageView alloc]initWithImage:cloudImage];
[img_bubble setFrame:CGRectMake(225, 0,85 , 80)];
img_buble_sender = [[UIImageView alloc]initWithImage:cloudImage1];
[img_buble_sender setFrame:CGRectMake(10,0,90,80)];
urlImage = [NSURL URLWithString:[[message_array objectAtIndex:indexPath.row] valueForKey:#"image"]];
asyncImage = [[AsyncImageView alloc]initWithFrame:CGRectMake(238, 10, 55, 55)];
[asyncImage loadImageFromURL:urlImage];
//images1=[[UIImageView alloc]initWithFrame:CGRectMake(238, 10,55 , 55)];
//[images1 setImageWithURL:urlImage];
}
Try this in your cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
//create new cell
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//common settings
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
cell.imageView.contentMode = UIViewContentModeScaleAspectFill;
cell.imageView.frame = CGRectMake(238, 10, 55, 55);
cell.imageView.clipsToBounds = YES;
}
else {
//cancel loading previous image for cell
[[AsyncImageLoader sharedLoader] cancelLoadingImagesForTarget:cell.imageView];
}
//set placeholder image or cell won't update when image is loaded
cell.imageView.image = [UIImage imageNamed:#"Placeholder.png"];
//load the image
cell.imageView.imageURL = [NSURL URLWithString:[[message_array objectAtIndex:indexPath.row];
return cell;
}
I'm not sure about which AsyncImageView you are using, but you could try this:
//UITableView
NSString *data_image;
data_image = [[message_array objectAtIndex:indexPath.row] valueForKey:#"img_thumb"];
NSLog(#"data_image---%#",data_image);
if (![data_image isEqualToString:#""])
{
img_bubble = [[UIImageView alloc]initWithImage:cloudImage];
[img_bubble setFrame:CGRectMake(225, 0,85 , 80)];
img_buble_sender = [[UIImageView alloc]initWithImage:cloudImage1];
[img_buble_sender setFrame:CGRectMake(10,0,90,80)];
urlImage = [NSURL URLWithString:[[message_array objectAtIndex:indexPath.row] valueForKey:#"image"]];
asyncImage = [[AsyncImageView alloc]initWithFrame:CGRectMake(238, 10, 55, 55)];
[asyncImage loadImageFromURL:urlImage];
[cell.contentView addSubview:asyncImage];
}

UIImage in UITableView displaying the other cell's image for a second

I am trying to load image asynchronously in a UIImage that resides in a table view cell. sometimes it shows the image from another cell for a second before it displays the correct one.
This is the code I am using
[[TMCache sharedCache] objectForKey:post[#"gif"] block:^(TMCache *cache, NSString *key, id object) {
if (object) {
if ([self isRowZeroVisible:indexPath.section]) {
[GIFLoader loadGIFData:object to:postGif for:feedTableView];
}
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
__block NSURL* url = [NSURL URLWithString:post[#"gif"]];
NSURLRequest* req = [NSURLRequest requestWithURL:url];
OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req];
[loader startRequestWithResponseHandler:nil
progress:nil
completion:^(NSData* receivedData, NSInteger httpStatusCode) {
if ([self isRowZeroVisible:indexPath.section]) {
[GIFLoader loadGIFData:receivedData to:postGif for:feedTableView];
}
[[TMCache sharedCache] setObject:receivedData forKey:post[#"gif"]];
} errorHandler:nil];
});
}];
[GIFLoader loadGIFData:receivedData to:postGif for:feedTableView]; is a method I created that loads GIFs in a uiimageview. it does that in a background thread and then assigns the Image in the main thread though.
Are there certain practices that I need to follow for async loading?
I am not sure what is wrong with my code. any help would be highly appreciated
edit
//Loading stuff into tableView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
#autoreleasepool {
//Type of Cells
static NSString *simpleTableImageIdentifier = #"gifCell";
static NSString *simpleTableBodyIdentifier = #"bodyCell";
static NSString *simpleTableActionsIdentifier = #"actionsCell";
UITableViewCell *cell = nil;
//Data that goes in the cell
NSDictionary *post = [dataArray objectAtIndex:indexPath.section];
//User info
UIImageView *userAvatar;
UILabel *postUserFullNameLabel;
UILabel *postUsername;
//GIF Date
OHAttributedLabel* gifDate = nil;
NSMutableAttributedString* gifDateString;
//Feed GIF
NSString *gifBody = [[NSString alloc]init];
OHAttributedLabel* attrLabel = nil;
NSMutableAttributedString* mas;
//Location
OHAttributedLabel* gifLocation = nil;
NSMutableAttributedString* gifLocationString;
UILabel *locationBg;
//Buttons
UIButton *btn1 =[[UIButton alloc] initWithFrame:CGRectMake(11,0,50,30)];
UIButton *btn2 =[[UIButton alloc] initWithFrame:CGRectMake(69,0,50,30)];
UIButton *btn3 =[[UIButton alloc] initWithFrame:CGRectMake(259,0,50,30)];
if (indexPath.row == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:simpleTableImageIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableImageIdentifier];
}
__block UIImageView *postGif= (UIImageView *)[cell viewWithTag:104];
postGif.image = nil;
[[TMCache sharedCache] objectForKey:post[#"gif"] block:^(TMCache *cache, NSString *key, id object) {
if (object) {
if ([self isRowZeroVisible:indexPath.section]) {
[GIFLoader loadGIFData:object to:postGif for:feedTableView];
}
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
__block NSURL* url = [NSURL URLWithString:post[#"gif"]];
NSURLRequest* req = [NSURLRequest requestWithURL:url];
OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req];
[loader startRequestWithResponseHandler:nil
progress:nil
completion:^(NSData* receivedData, NSInteger httpStatusCode) {
if ([self isRowZeroVisible:indexPath.section]) {
[GIFLoader loadGIFData:receivedData to:postGif for:feedTableView];
}
[[TMCache sharedCache] setObject:receivedData forKey:post[#"gif"]];
} errorHandler:nil];
});
}];
postGif.layer.cornerRadius = 2.0;
postGif.layer.masksToBounds = YES;
postGif.clipsToBounds = YES;
locationBg = (UILabel *)[cell viewWithTag:106];
userAvatar = (UIImageView *)[cell viewWithTag:100];
if ([post [#"user_avatar"] length ] > 0) {
NSString *img = [#"https://d1f7i732a4e7fw.cloudfront.net/" stringByAppendingString:post [#"user_avatar"]];
[userAvatar setImageWithURL:[NSURL URLWithString:img] placeholderImage:[UIImage imageNamed:#"userDefaultPicture.png"]];
}else{
userAvatar.image = [UIImage imageNamed:#"userDefaultPicture.png"];
}
userAvatar.layer.cornerRadius = 18.0;
userAvatar.layer.borderWidth = 1.0;
userAvatar.layer.borderColor = (__bridge CGColorRef)([UIColor lightGrayColor]);
userAvatar.clipsToBounds = YES;
postUserFullNameLabel = (UILabel *)[cell viewWithTag:101];
postUserFullNameLabel.text = post[#"user_fullname"];
postUsername = (UILabel *)[cell viewWithTag:102];
postUsername.text = [NSString stringWithFormat:#"#%#",post[#"user_username"]];
gifDate = [[OHAttributedLabel alloc] initWithFrame:CGRectMake(246,9,60,21)];
gifDate.autoresizingMask = UIViewAutoresizingNone;
gifDate.centerVertically = YES;
gifDate.highlightedTextColor = [UIColor whiteColor];
gifDate.tag = 103;
gifDate.backgroundColor = [UIColor clearColor];
gifDate.extendBottomToFit = NO;
gifDateString = [NSMutableAttributedString attributedStringWithString:[NSString stringWithFormat:#"\ue003 %#",post[#"date"]]];
[gifDateString setFont:[UIFont fontWithName:#"Helvetica Neue" size:12.0]];
[gifDateString setFont:[UIFont fontWithName:#"icomoon" size:10.0] range:NSMakeRange(0,1)];
[gifDateString setTextColor:[UIColor whiteColor]];
[gifDateString setTextAlignment:kCTTextAlignmentRight lineBreakMode:kCTLineBreakByTruncatingTail];
[OHASBasicMarkupParser processMarkupInAttributedString:gifDateString];
gifDate.attributedText = gifDateString;
if (!(post[#"latitude"] == (id)[NSNull null])){
//Location of the Post
gifLocation = [[OHAttributedLabel alloc] initWithFrame:CGRectMake(165,27,141,21)];
gifLocation.autoresizingMask = UIViewAutoresizingNone;
gifLocation.centerVertically = YES;
gifLocation.highlightedTextColor = [UIColor whiteColor];
gifLocation.tag = 107;
gifLocation.backgroundColor = [UIColor clearColor];
gifLocation.extendBottomToFit = NO;
gifLocationString = [NSMutableAttributedString attributedStringWithString:[NSString stringWithFormat:#"\uf041 %#",post[#"locationName"]]];
[gifLocationString setFont:[UIFont fontWithName:#"Helvetica Neue" size:12.0]];
[gifLocationString setFont:[UIFont fontWithName:#"icomoon" size:12.0] range:NSMakeRange(0,1)];
[gifLocationString setTextColor:[UIColor whiteColor]];
[gifLocationString setTextAlignment:kCTTextAlignmentRight lineBreakMode:kCTLineBreakByTruncatingTail];
[OHASBasicMarkupParser processMarkupInAttributedString:gifLocationString];
gifLocation.attributedText = gifLocationString;
}
}
else if (indexPath.row == 1) {
cell = [tableView dequeueReusableCellWithIdentifier:simpleTableBodyIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableBodyIdentifier];
}
//Body of GIF
// Add more from here http://www.easyapns.com/iphone-emoji-alerts
gifBody = post[#"body"];
attrLabel = [[OHAttributedLabel alloc] initWithFrame:CGRectMake(10,5,kLabelWidth,tableView.rowHeight-2*kLabelVMargin)];
attrLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight;
attrLabel.centerVertically = NO;
attrLabel.automaticallyAddLinksForType = NSTextCheckingAllTypes;
attrLabel.delegate = self;
attrLabel.highlightedTextColor = UIColorFromRGB(0x333333);
attrLabel.tag = kAttributedLabelTag;
attrLabel.backgroundColor = [UIColor clearColor];
attrLabel.extendBottomToFit = YES;
[cell.contentView addSubview:attrLabel];
attrLabel = (OHAttributedLabel*)[cell viewWithTag:kAttributedLabelTag];
mas = [NSMutableAttributedString attributedStringWithString:gifBody];
[mas setFont:[UIFont fontWithName:#"Helvetica Neue" size:14.0]];
[mas setTextColor:UIColorFromRGB(0x333333)];
[mas setTextAlignment:kCTTextAlignmentLeft lineBreakMode:kCTLineBreakByWordWrapping];
[OHASBasicMarkupParser processMarkupInAttributedString:mas];
attrLabel.attributedText = mas;
}
else if (indexPath.row == 2) {
cell = [tableView dequeueReusableCellWithIdentifier:simpleTableActionsIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableActionsIdentifier];
}
[self customizeButtons:btn1];
btn1.tag = (indexPath.section +1)*200;
btn1.titleLabel.font = [UIFont fontWithName:#"icomoon" size:16.0];
if ([post[#"is_Favoring"] boolValue]) {
[btn1 setTitleColor:UIColorFromRGB(0xE4717A) forState:UIControlStateNormal];
}else{
[btn1 setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
}
[btn1 setTitle:#"\uf004" forState:UIControlStateNormal];
btn1.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
[btn1 addTarget:self
action:#selector(favorAction:)
forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:btn1];
[self customizeButtons:btn2];
btn2.tag = (indexPath.section +1)*2000;
btn2.titleLabel.font = [UIFont fontWithName:#"icomoon" size:16.0];
[btn2 setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
[btn2 setTitle:#"\ue000" forState:UIControlStateNormal];
[cell.contentView addSubview:btn2];
btn2.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
[btn2 addTarget:self
action:#selector(commentAction:)
forControlEvents:UIControlEventTouchUpInside];
[self customizeButtons:btn3];
btn3.titleLabel.font = [UIFont fontWithName:#"icomoon" size:16.0];
[btn3 setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
[btn3 setTitle:#"\ue001" forState:UIControlStateNormal];
btn3.tag = (indexPath.section +1)*20000;
[cell.contentView addSubview:btn3];
btn3.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
[btn3 addTarget:self
action:#selector(otherAction:)
forControlEvents:UIControlEventTouchUpInside];
}
//Paginiation
if (indexPath.section == [dataArray count]-4 && indexPath.row == 1) {
[self loadNextPage];
}
return cell;
}
}
The reason you are seeing an image from another cell is that for efficiency's sake, table cells are reused. To get around this problem, set your image to nil after you dequeue the reusable cell in tableView:cellForRowAtIndexPath:.
First, you shouldn't be doing all of that stuff in cellForRowAtIndexPath.
You should subclass UITableViewCell and layout the cell in it's own class.
Cell for row at indexPath should load the cell and populate data. Not layout loads of controls.
Second, once you've done this you can call...
- (void)prepareForReuse
{
self.imageView.image = nil;
}
This will clear the imageView on dequeue of the cell so that if there is a delay loading hte image then you only see a blank imageView rather than the image that was in there previously.

Resources