How to stop NSInvocationOperation and NSOperationQueue - iphone

I am using [NSOperationQueue mainQueue] and NSInvocationOperation in table view cellforRowAtIndexPath method to load images from web in background.But it is not stopping after download image. Here is my code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell=[mytable dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
imageLabel=(UIImageView *)[cell viewWithTag:5];
UIImage *image=[dict objectForKey:[appSmallLogos objectAtIndex:indexPath.row]];
if (image) {
imageLabel.image=image;
} else {
NSURL *on=[appSmallLogos objectAtIndex:indexPath.row];
NSString *on1=[appNames objectAtIndex:indexPath.row];
NSMutableArray *array=[[NSMutableArray alloc] initWithObjects:on,on1,indexPath, nil];
operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(didGetAlbums:) object:arr];
q =[NSOperationQueue mainQueue];
[q addOperation:operation];
imageLabel.image=[dict objectForKey:on1];
}
return cell;
}
//didgetalbums method
- (void )didGetAlbums: (NSMutableArray* )url
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *data=[NSData dataWithContentsOfURL:[url objectAtIndex:0]];
UIImage *image1 = [UIImage imageWithData:data];
dispatch_sync(dispatch_get_main_queue(), ^{
[dict setObject:image1 forKey:[url objectAtIndex:1]];
});
});
//reload the requested cell after download image
[self. mytable beginUpdates];
[self. mytable reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[url objectAtIndex:2], nil] withRowAnimation:UITableViewRowAnimationNone];
[self. mytable endUpdates]; // imageLabel.image=[dict objectForKey:[appSmallLogos objectAtIndex:indexPath.row]];
}

Related

Slow UITableView with Facebook Image

I have a uitableview and each cells have an image from facebook image profile and 2 uilabels (from singleton, not an internet request)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString *CellIdentifier = #"MenuCell";
MenuCellViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[MenuCellViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//Singleton
DataModel *m = [DataModel getModel];
switch ([indexPath section]) {
case 0: //Only Header
break;
case 1: //My cells
{
//If footer - set footer background
if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section] - 1){
[cell setBackgroundView:[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"imgFooter.png"]]];
//Else - set normal cell background
} else {
[cell setBackgroundView:[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"img.png"]]];
}
//Get Facebook image
strForImg = [[NSString alloc] initWithFormat:#"https://graph.facebook.com/%#/picture?type=square",[[[m list] objectAtIndex:indexPath.row] objectForKey:#"id"]];
url =[NSURL URLWithString:strForImg];
img = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
[cell.imgProfile setImage:img];
//Set some text (uilabels)
cell.lblNom.text = [[[m list] objectAtIndex:indexPath.row] objectForKey:#"name"];
cell.lblTour.text = [[[m list] objectAtIndex:indexPath.row] objectForKey:#"description"];
break;
}
}
}
This code is very slow and freezes the tableview as it loads from facebook the profile images of each cell dynamically.
I tried doing with a dispatch like this
case 1://My cells
{
if (indexPath.row == [tableView numberOfRowsInSection:indexPath.section] - 1){
[cell setBackgroundView:[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"imgFooter.png"]]];
} else {
[cell setBackgroundView:[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"img.png"]]];
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
dispatch_sync(dispatch_get_main_queue(), ^{
strForImg = [[NSString alloc] initWithFormat:#"https://graph.facebook.com/%#/picture?type=square",[[list objectAtIndex:indexPath.row] objectForKey:#"id"]];
url =[NSURL URLWithString:strForImg];
img = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
[cell.imgProfile setImage:img];
});
});
cell.lblNom.text = [[[m list] objectAtIndex:indexPath.row] objectForKey:#"name"];
cell.lblTour.text = [[[m list] objectAtIndex:indexPath.row] objectForKey:#"description"];
break;
}
The speed has slighty increased but it is still FREEZING when scrolling.
Is my dispatch not correct ? (I have just discovered it, maybe it is not well used).
Or is there any better method ?
I like the facebook friend picker. It puts a default profile image and refreshes the correct image profile when it is received from internet. How is this magic done ? :)
Fix this block:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
strForImg = [[NSString alloc] initWithFormat:#"https://graph.facebook.com/%#/picture?type=square",[[list objectAtIndex:indexPath.row] objectForKey:#"id"]];
url =[NSURL URLWithString:strForImg];
img = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
dispatch_sync(dispatch_get_main_queue(), ^{
[cell.imgProfile setImage:img];
});
});

Image lazy loading in table view

I want to use lazy loading of images concept in my table view. My array of image rul string is ( MSMutableArray ) "images". How can I implement this in cellForRowAtIndexPath.
It looks like:
-(UITableViewCell *) tableView:(UITableView *)AtableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell=[searchtable dequeueReusableCellWithIdentifier:#"cell"];
if(!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
cell.textLabel.font=[UIFont systemFontOfSize:12];
cell.imageView.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[appSmallLogos objectAtIndex:indexPath.row]]]];
cell.detailTextLabel.text=[appReleaseDates objectAtIndex:indexPath.row];
}
return cell;
}
Try this code :
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.frame = CGRectMake(your bounds);
[cell addSubview:indicator];
[indicator bringSubviewToFront:self.view];
[indicator startAnimating];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
//This is what you will load lazily
NSString *u=[NSString stringWithContentsOfFile:r.url encoding:NSUTF8StringEncoding error:nil];
NSURL *imageURL=url;
NSData *image=[NSData dataWithContentsOfURL:imageURL];
dispatch_sync(dispatch_get_main_queue(), ^{
CustomCell *cell = (CustomCell *)[tableView cellForRowAtIndexPath:indexPath];
cell.imageView.image=[UIImage imageWithData:image];
[cell setNeedsLayout];
[indicator stopAnimating];
});
});
cell.cellDescription.text=r.url;// this is which you want to add in first time.
I am not sure but try it.
You can use the SDWebImage library, the library will download and cache the image asynchronously. by passing the url to it as argument
- (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 setImageWithURL: method to load the web image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
TableCellLayout *cell = (TableCellLayout *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[TableCellLayout alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.cellName = [[array valueForKey:#"name"] objectAtIndex:indexPath.row];
cell.cellImage = [UIImage imageNamed:#"placeholder.png"]; // add a placeholder
NSString *imageURL = [[array valueForKey:#"imageLink"] objectAtIndex:indexPath.row];
NSURL *theURL = [NSURL URLWithString:imageURL];
if (asynchronousImageLoader == nil){
asynchronousImageLoader = [[AsynchronousImages alloc] init];
}
[asynchronousImageLoader loadImageFromURL:theURL];
cell.cellImage = asynchronousImageLoader.image;
return cell;
}
I finally managed to do it setting the image with:
– performSelectorOnMainThread:withObject:waitUntilDone:
After the image is downloaded

Image Loading Animation issue using GCD

Hi I'm using GCD to load image in the uitableview . Now, the problem is image animation. I called three images from server it loads into the cell but i got 3 problems
1) Single image is repeated in all three cells
2) first and last cell images blinking and changing
3) when the image changed, it is repeated in all cells.
Even though i gave animation none still it animates i.e. Blinking
Code:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
[imageArray retain];
//get a dispatch queue
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 *image = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[imageArray objectAtIndex:indexPath.row]]];
//this will set the image when loading is finished
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = [UIImage imageWithData:image];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
});
});
return cell;
}
You should not download images in this place.
If You don't have too many rows, do this in eg. viewDidLoad and save downloaded images to new mutable array.
Something like this:
- (void) viewDidLoad {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
int row = 0;
self.thumbnails = [NSMutableArray array];
for (NSString *imageURLString in imageArray) {
//Your way of download images
NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:imageURLString]];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
[self.thumbnails addObject:image];
NSArray *indexes = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:row inSection:1]];
[self.tableViewOutlet reloadRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationNone];
});
row++;
}
});
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.thumbnails && [self.thumbnails count] > indexPath.row) {
cell.attachmentImageView.image = [self.thumbnails objectAtIndex:indexPath.row];
} else {
cell.attachmentImageView.image = nil;
}
}

Give Error 'mach_msg_trap' error

when run the following code it give proper result but when go to another view and go back an further search it give the 'mach_msg_trap' error
- (void)viewWillAppear:(BOOL)animated {
AppDeleget= [[UIApplication sharedApplication] delegate];
ProcessView *Process=[[ProcessView alloc] init];
[Process SearchProperty:AppDeleget.PropertyURL page:AppDeleget.Page];
[Process release];
for(NSDictionary *status in AppDeleget.statuses)
{
NSMutableString *pic_string = [[NSMutableString alloc] initWithFormat:#"%#",[status objectForKey:#"picture"]];
if([pic_string isEqualToString:#""])
{
[ListPhotos addObject:#"NA"];
}
else
{
NSString *str= [[[status objectForKey:#"picture"] valueForKey:#"url"] objectAtIndex:0];
[ListPhotos addObject:str];
[str release];
}
}
[NSThread detachNewThreadSelector:#selector(LoadImage) toTarget:self withObject:nil];
[AppDeleget.MyProgressView stopAnimating];
[AppDeleget.Progress removeFromSuperview];
[super viewWillAppear:animated];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
TableCell *cell = (TableCell *)[TableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[TableCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// NSString *bedsbaths=[NSString stringWithFormat:#"Beds:%# Baths:%#",[[AppDeleget.statuses valueForKey:#"beds"] objectAtIndex:indexPath.row],[[AppDeleget.statuses valueForKey:#"baths"] objectAtIndex:indexPath.row]];
cell.mlsno.text=[[AppDeleget.statuses valueForKey:#"mlsno"] objectAtIndex:indexPath.row];
cell.price.text=[[AppDeleget.statuses valueForKey:#"price"] objectAtIndex:indexPath.row];
cell.address.text=[[AppDeleget.statuses valueForKey:#"address"] objectAtIndex:indexPath.row];
// cell.bedsbaths.text=bedsbaths;
cell.bedsbaths.text=[[AppDeleget.statuses valueForKey:#"dispDetails"] objectAtIndex:indexPath.row];
cell.accessoryType=UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
-(void)LoadImage
{
for(int x=0;x<[ListPhotos count];x++)
{
if ([ListPhotos objectAtIndex:x] == #"NA")
{
UIImage *img = [UIImage imageNamed:#"No_image.png"];
[self performSelectorOnMainThread:#selector(downloadDone:) withObject:img waitUntilDone:NO];
}
else
{
NSData *imageData =[ListPhotos objectAtIndex:x];
id path = imageData;
NSURL *url = [NSURL URLWithString:path];
NSLog(#"%#",url);
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
[self performSelectorOnMainThread:#selector(downloadDone:) withObject:img waitUntilDone:NO];
}
}
}
-(void)downloadDone:(UIImage*)img {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:count inSection:0];
if(img == nil)
{
TableCell *cell = (TableCell *)[TableView cellForRowAtIndexPath:indexPath];
cell.myImageView.image=[UIImage imageNamed:#"No_image.png"];
++count;
[TableView reloadData];
}
else
{
TableCell *cell = (TableCell *)[TableView cellForRowAtIndexPath:indexPath];
cell.myImageView.image=img;
++count;
[TableView reloadData];
}
}
You're releasing objects which were not allocated:
NSString *str= [[[status objectForKey:#"picture"] valueForKey:#"url"] objectAtIndex:0];
[ListPhotos addObject:str];
[str release];
Here, 'str' shouldn't be released, because it's an autoreleased object.

Help me on loading the images on table view using NSOperationQueue

Kindly look the below code..i found from web
- (void) loadData {
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(loadDataWithOperation) object:nil];
[queue addOperation:operation];
[operation release];
}
- (void) loadDataWithOperation {
NSURL *dataURL = [NSURL URLWithString:#"http://icodeblog.com/samples/nsoperation/data.plist"];
NSArray *tmp_array = [NSArray arrayWithContentsOfURL:dataURL];
for(NSString *str in tmp_array) {
[self.array addObject:str];
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[cell.textLabel setText:[self.array objectAtIndex:indexPath.row]];
return cell;
}
I have found the above code which loads the text from the web without any problem.( i mean gui is not hanging ).like wise i want to load images into the table view.for that i have wriiten the below code.
- (void) loadDataWithOperation {
NSString *Img_id, *Img_name, *DynamicImgUrl;
Img_id = xmltag.equip_id;
Img_name = xmltag.image;
DynamicImgUrl = [NSString stringWithFormat:#"http://test.com/pics/equipment/%#/%#",Img_id, Img_name];
NSURL *ImageUrl = [NSURL URLWithString:DynamicImgUrl];
//UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:ImageUrl]];
NSArray *tmp_array = [NSArray arrayWithContentsOfURL:ImageUrl];
for(NSString *str in tmp_array) {
[self.array addObject:str];
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}
Am i correct here? how can i go with adding into the table view...
Kindly help me out...
U are seeking to display images on Tableview from URL, when u download image from url we need to consider some issues, it will freeze ur table view if u goahead with ordinary loading image.
i suggest u look at LazyLoading image
u see this link http://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html
Download this sample and get to know the things