Currently, I am developing an app in which I have fetch Facebook album photo & display it as
gallery view asynchronously using Table view & put images on button of table view cell using below code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"particulars..:%d",[particular count]);
int count=self.particular.count%3;
if(count==0)
{
return self.particular.count/3;
}
else
{
return (self.particular.count/3) +1;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell1";
CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"CustomTableViewCell" owner:self options:nil];
cell = customcell;
}
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSString *buttonurl=[self.particular objectAtIndex:((indexPath.row)*3)+0];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: buttonurl]];
if ( data == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:data];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor=[UIColor clearColor];
[cell.first setBackgroundImage:image forState:UIControlStateNormal] ;
[cell.first addTarget:self action:#selector(original:) forControlEvents:UIControlEventTouchUpInside];
[cell.first setContentMode:UIViewContentModeCenter] ;
cell.first.layer.cornerRadius = 10.0;
cell.first.layer.borderColor = [[UIColor grayColor]CGColor];
cell.first.layer.borderWidth = 1.0f;
cell.first.backgroundColor=[UIColor clearColor];
cell.first.tag = ((indexPath.row)*3)+1 ;
[spinner stopAnimating];
});
[data release];
});
if(((indexPath.row)*3)+3<[particular count])
{
UIActivityIndicatorView *spinner2 = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
UIActivityIndicatorView *spinner3 = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
//spinner2.backgroundColor=[UIColor blackColor];
CGRect frame= cell.second.frame;
spinner2.frame=frame;
//spinner2.frame=CGRectMake(112, y, 106, 106);
spinner2.hidesWhenStopped = YES;
[cell.second addSubview:spinner2];
[spinner2 startAnimating];
CGRect frame2= cell.third.frame;
spinner3.frame=frame2;
spinner3.hidesWhenStopped = YES;
[cell.third addSubview:spinner3];
[spinner3 startAnimating];
dispatch_async(dispatch_get_global_queue(0,0), ^
{
NSString *buttonurl=[self.particular objectAtIndex:((indexPath.row)*3)+1];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: buttonurl]];
NSString *buttonurl1=[self.particular objectAtIndex:((indexPath.row)*3)+2];
NSData * data1 = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: buttonurl1]];
if ( data == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^
{
UIImage *image = [UIImage imageWithData:data];
UIImage *image1 = [UIImage imageWithData:data1];
[cell.second setBackgroundImage:image forState:UIControlStateNormal] ;
[cell.second addTarget:self action:#selector(original:) forControlEvents:UIControlEventTouchUpInside];
[cell.second setContentMode:UIViewContentModeCenter] ;
cell.second.layer.cornerRadius = 10.0;
cell.second.layer.borderColor = [[UIColor grayColor]CGColor];
cell.second.layer.borderWidth = 1.0f;
cell.second.backgroundColor=[UIColor clearColor];
cell.second.tag = ((indexPath.row)*3)+2 ;
NSLog(#"cell.second.tag:%d",cell.second.tag);
[cell.third setBackgroundImage:image1 forState:UIControlStateNormal] ;
[cell.third addTarget:self action:#selector(original:) forControlEvents:UIControlEventTouchUpInside];
[cell.third setContentMode:UIViewContentModeCenter] ;
cell.third.layer.cornerRadius = 10.0;
cell.third.layer.borderColor = [[UIColor grayColor]CGColor];
cell.third.layer.borderWidth = 1.0f;
cell.third.backgroundColor=[UIColor clearColor];
cell.third.tag = ((indexPath.row)*3)+3 ;
NSLog(#"cell.third.tag:%d",cell.third.tag);
[spinner2 stopAnimating];
[spinner3 stopAnimating];
});
[data release];
});
}
else if(((indexPath.row)*3)+2<[particular count])
{
UIActivityIndicatorView *spinner2 = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
CGRect frame1 = CGRectMake(120, y, 106, 107);
spinner2.frame=frame1;
spinner2.hidesWhenStopped = YES;
[cell.second addSubview:spinner2];
[spinner2 startAnimating];
dispatch_async(dispatch_get_global_queue(0,0), ^
{
NSString *buttonurl=[self.particular objectAtIndex:((indexPath.row)*3)+1];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: buttonurl]];
if ( data == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^
{
UIImage *image = [UIImage imageWithData:data];
[cell.second setBackgroundImage:image forState:UIControlStateNormal] ;
[cell.second addTarget:self action:#selector(original:) forControlEvents:UIControlEventTouchUpInside];
[cell.second setContentMode:UIViewContentModeCenter] ;
cell.second.layer.cornerRadius = 10.0;
cell.second.layer.borderColor = [[UIColor grayColor]CGColor];
cell.second.layer.borderWidth = 1.0f;
cell.second.backgroundColor=[UIColor clearColor];
cell.second.tag = ((indexPath.row)*3)+2 ;
NSLog(#"cell.second.tag:%d",cell.second.tag);
[spinner2 stopAnimating];
});
[data release];
});
}
else
{
cell.second.hidden = YES;
cell.third.hidden = YES;
}
y=y+106;
return cell;
}
This code is working fine for me but the problem is that when images load into button contain by table view cell then if we scroll down then it slowly show images but after that when we scroll up to see previously load images then images disappear & it again load from starting & take times.So please tell where i am doing mistake in code or how can I solve this?
I'd suggest you to use this AsyncImageView. I've used it and it work wonders. To call this API:
ASyncImage *img_EventImag = alloc with frame;
NSURL *url = yourPhotoPath;
[img_EventImage loadImageFromURL:photoPath];
[self.view addSubView:img_EventImage]; // In your case you'll add in your TableViewCell.
It's same as using UIImageView. Easy and it does most of the things for you. AsyncImageView includes both a simple category on UIImageView for loading and displaying images asynchronously on iOS so that they do not lock up the UI, and a UIImageView subclass for more advanced features. AsyncImageView works with URLs so it can be used with either local or remote files.
Loaded/downloaded images are cached in memory and are automatically cleaned up in the event of a memory warning. The AsyncImageView operates independently of the UIImage cache, but by default any images located in the root of the application bundle will be stored in the UIImage cache instead, avoiding any duplication of cached images.
The library can also be used to load and cache images independently of a UIImageView as it provides direct access to the underlying loading and caching classes.
There are some custom libraries which do the job very well for you
AsynchImageView
SDWebImage
AFNetworking Image Extension (if you are using AF )
It is working the way it should do. When you scroll a table view is like if the cells that disappeared have been released and when you scroll back the cell are dequeued.
So, you should use a solution for caching the images so that they don't need to be loaded again, such as EGOImageView (here), AsyncImageView, SDWebImage etc.
Here is a solution with out using dispatch_async.If you are getting the URL from services than use this method NSObject where service is called
-(void)loadProfilePicWithURL:(NSString *)strUrl tagV:(NSInteger)tagV{
isProfilePicLoaded = NO;
//set media tag as indexPath.row
//call this method from cellForRowAtIndexpPath
//Pass the image URL --> strProfilePicURL
//Load the image in bg and set to imgProfilePic
//After loaded, send a notification with tag to table view to update the cell
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:strUrl]];
imgProfilePic=[UIImage imageWithData:data];
isProfilePicLoaded = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:#"reloadTableViewCell" object:[NSNumber numberWithInteger:tagV]];
}
Call this method from cellForRowAtIndexPath
[self performSelectorInBackground:#selector(loadPic:) withObject:[NSNumber numberWithInteger:indexPath.row]];
implement
-(void)loadPic: (id )indexPath{
NSInteger conV=[indexPath integerValue];
NSObject *object=[Array objectAtIndex:conV];
[object loadProfilePicWithURL:object.url tagV:conV];
}
Add Observer for the notification in NSObject
-(void)reloadTableViewCell:(NSNotification *)note{
NSInteger mediaTag = [[note object] integerValue];
[self reloadCellImage:mediaTag];
}
Re-load the particular cell in the table.
-(void)reloadCellImage:(NSInteger)row{
NSObject *object = [self.receivedArray objectAtIndex:row];
NSIndexPath* rowToReload = [NSIndexPath indexPathForRow:row inSection:0];
customCell *cell = (customCell *)[self.tableView cellForRowAtIndexPath:rowToReload];
[cell.imgVw setImage:object.image];}
Related
How to implement lazy loading to uiscroll view
I am taking 15 images from the web service and add it to UIscrollview
I want to lad the scroll view with temporary image and when the image is ready it can add the image to uiscrollview
-(void)loadthscroll:(NSMutableArray *)idarray:(NSMutableArray *)imgarray
{
/*************scroll for scroll in in theater******************/
scrollview_intheater= [[UIScrollView alloc] initWithFrame:CGRectMake(0, btn_thhead.frame.size.height,view_banner.frame.size.width, view_intheater.frame.size.height-btn_thhead.frame.size.height)];
[view_intheater addSubview:scrollview_intheater];
[scrollview_thcsoon removeFromSuperview];
adj=5;
currentx=5;
for(int i=0;i<[imgarray count];i++)
{
btn_theater_ct = [UIButton buttonWithType:UIButtonTypeCustom];
btn_theater_ct.frame=CGRectMake(currentx, 5, 95, 120);
[btn_theater_ct addTarget:self action:#selector(theaterAction:) forControlEvents:UIControlEventTouchDown];
[scrollview_intheater addSubview:btn_theater_ct];
addr = [imgarray objectAtIndex:i];
addr = [addr stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
//NSLog(#"addr-------%#",addr);
data_theater = [NSData dataWithContentsOfURL:[NSURL URLWithString:addr ] ];
[btn_theater_ct setBackgroundImage:[UIImage imageWithData:data_theater] forState:UIControlStateNormal];
currentx +=btn_theater_ct.frame.size.width+adj;
btn_theater_ct.tag=i;
[scrollview_intheater setContentSize:CGSizeMake(currentx,0)];
NSLog(#"add th scroll--%d----%d",[imgarray count],i);
}
}
I face the same issue before few days but i fixed it now by
importing
#import "UIImageView+AFNetworking.h"
and implementing its method
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage;
to use this u have to use AFNetworking class
Set up the whole UIScrollView with a loading image
Create a method which exchanges a given image and update the content size if needed
Add a routine do download the image
Now you can setup the UIScrollView and call the routine to download. Then when the download is done call the method to exchange the image and you are done.
Try to study GCD(GrandCentralDispatch) and work with your scenario's.
May be this will suits you.
-(void)loadthscroll:(NSMutableArray *)idarray:(NSMutableArray *)imgarray
{
scrollview_intheater= [[UIScrollView alloc] initWithFrame:CGRectMake(0, btn_thhead.frame.size.height,view_banner.frame.size.width, view_intheater.frame.size.height-btn_thhead.frame.size.height)];
[view_intheater addSubview:scrollview_intheater];
[scrollview_thcsoon removeFromSuperview];
adj=5;
currentx=5;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
//Here, do your iteration part like parsing URL from array and hitting the service which is background thread.
for(int i=0;i<[imgarray count];i++)
{
btn_theater_ct = [UIButton buttonWithType:UIButtonTypeCustom];
btn_theater_ct.frame=CGRectMake(currentx, 5, 95, 120);
[btn_theater_ct addTarget:self action:#selector(theaterAction:) forControlEvents:UIControlEventTouchDown];
[scrollview_intheater addSubview:btn_theater_ct];
currentx +=btn_theater_ct.frame.size.width+adj;
[scrollview_intheater setContentSize:CGSizeMake(currentx,0)];
NSLog(#"add th scroll--%d----%d",[imgarray count],i);
addr = [imgarray objectAtIndex:i];
addr = [addr stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
//NSLog(#"addr-------%#",addr);
data_theater = [NSData dataWithContentsOfURL:[NSURL URLWithString:addr ] ];
UIImage *receivedImage = [UIImage imageWithData:data_theater];
}
dispatch_async(dispatch_get_main_queue(), ^{
//Here, do your UI work like set the background image which is include in main thread
if([receivedImage isKindOfClass:[UIImage class]])
{
[btn_theater_ct setBackgroundImage: receivedImage];
btn_theater_ct.tag=i;
}
});
});
}
I am using AsyncImageView classes to apply lazy loading on UITableView. And want to apply activity indicator on image view until the image is loaded on cell. Below is my code i am trying.
// AsyncIamgeView.m
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
//[connection release];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
indicator.center = CGPointMake(15, 15);
connection=nil;
if ([[self subviews] count]>0) {
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImage *imgData = [UIImage imageWithData:data];
UIImageView* imageView = [[UIImageView alloc]init];
[imageView addSubview:indicator];
[indicator startAnimating];
if(imgData == nil)
{
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"NoImagenew.png"]];
//[indicator stopAnimating];
}
else{
imageView = [[UIImageView alloc] initWithImage:imgData];
// [indicator stopAnimating];
}
//imageView.contentMode = UIViewContentModeScaleAspectFit;
//imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth || UIViewAutoresizingFlexibleHeight );
//[imageView sizeToFit];
[self addSubview:imageView];
imageView.frame = self.bounds;
//imageView.frame = CGRectMake(0, 0, 85, 94);
[imageView setNeedsLayout];
[self setNeedsLayout];
//[data release];
data=nil;
}
// cellForRowAtIndexPath method.
asyncImageView = [[AsyncImageView alloc]initWithFrame:CGRectMake(1, 3, 85, 54)];
[asyncImageView loadImageFromURL:[NSURL URLWithString:imageUrlString]];
[cell.contentView addSubview:asyncImageView];
This code shows activity indicator but when image is loaded after that not before loading images. Please guide for above.
You have to create AsyncImageView object instead of UIImageView, then it will automatically add indicator to your view
AsyncImageView *imageView = [[AsyncImageView alloc] initWithFrame:CGRectMake(1, 3, 85, 54)];
[cell addSubview:imageView];
//cancel loading previous image for cell
[[AsyncImageLoader sharedLoader] cancelLoadingImagesForTarget:imageView];
//load the image
imageView.imageURL = [imageURLs objectAtIndex:indexPath.row];
Here is an example of this
Currently you are adding activity indicator when your image is downloaded.
Here is the simple idea, hope you can implement this in your code
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when your connection receives a response
// add your activity indication here and start animating
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// This method is called when your image is downloaded.
// remove your activity indicator or stop animating here
}
Hope u downloaded AsyncImageView from https://github.com/nicklockwood/AsyncImageView. By default, it has the feature to show activity indicator. You just dont need to add or remove any code by yourself to get this feature works. Just call loadImageWithURL.
I think u are using asynimageview classs, In that by default you will get the loader in the cell itself .
AysncImageView already has a loader.
You won't see it if your background is black since it loads the default activity indicator.
So, just set the activityIndicatorStyle property for your AsyncImageView object based on your background.
In my case, my background was black, so I used the following code :
asyncImgView.activityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
My code parts in two:
The first is the "cellForRowAtIndexPath" method for my table view. In this table view i'm supposed to show 3 buttons in each cell and each button is a different image. Images are in an NSMutableArray call "photosArray". It looks like this.
-(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];
}
if (photosArray.count > 0) {
for (int i = 0; i < 3; i++) {
if (photosArray.count > photoCounter) {
//position the UiButtons in the scrollView
CGRect frame = CGRectMake((i*100) + 30, 5, 60, 60);
//Create the UIbuttons
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTag:i];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
button.frame = frame;
button.layer.borderWidth = 2;
button.layer.cornerRadius = 5;
button.clipsToBounds = YES;
//Add images to the button
NSLog(#"PhotosArray count is: %d",photosArray.count);
if ([[photosArray objectAtIndex:0] isKindOfClass:[UIImage class]]) {
NSLog(#"UIImage class true");
}
if ([[photosArray objectAtIndex:0] isMemberOfClass:[UIImage class]]) {
NSLog(#"UIImage class true");
}
UIImage *btnImg = [self.photosArray objectAtIndex:photoCounter];
//UIImage *btnImg2 = [UIImage imageNamed:#"GameOver"];
photoCounter++;
[button setBackgroundImage:btnImg forState:UIControlStateNormal];
[cell.contentView addSubview:button];
}
}
}else{
UILabel *noImages = [[UILabel alloc] initWithFrame:CGRectMake(0, 25, 320, 20)];
noImages.text = #"No images";
noImages.textAlignment = NSTextAlignmentCenter;
[cell.contentView addSubview:noImages];
}
return cell;
}
The second part is where I load my pictures into "photosArray". I am using WSAssetPicker to load multiple photos from my asset library.
Here is the code:
- (void)assetPickerController:(WSAssetPickerController *)sender didFinishPickingMediaWithAssets:(NSArray *)assets
{
// Dismiss the WSAssetPickerController.
[self dismissViewControllerAnimated:YES completion:^{
arep = [[ALAssetRepresentation alloc] init];
for (ALAsset *asset in assets) {
UIImage *imageA = [[UIImage alloc] initWithCGImage:asset.defaultRepresentation.fullScreenImage];
[self.photosArray addObject:imageA];
}
NSLog(#"%d",photosArray.count);
photoCounter = 0;
[self.tableView reloadData];
}];
}
And now for the issue, the buttons that are created have no image in it. I only get a transparent button with a border and rounded corners.
Why is that?
It was recently brought to my attention that I omitted an important piece from the README (which is now updated).
It is necessary to hold a strong reference of WSAssetPickerController if you are accessing ALAsset objects in the dismissViewControllerAnimated:completion: completion block.
If you do not hold a strong reference to the picker controller before calling dismissViewControllerAnimated:completion: the picker controller will be released before the completion block is executed resulting in the ALAssetsLibrary (used internally in the WSAssetPicker code) from being released before you try to access the ALAssets in the assets array passed in the assetPickerController:didFinishPickingMediaWithAssets: delegate method.
If ALAssetsLibrary gets released, the ALAssets owned by the ALAssetsLibrary will expire and calls to asset.defaultRepresentation.fullScreenImage will return null.
The following will preserve the ALAssetsLibrary while dismissing the picker controller's view:
- (void)assetPickerController:(WSAssetPickerController *)sender didFinishPickingMediaWithAssets:(NSArray *)assets
{
// Hang on to the picker to avoid ALAssetsLibrary from being released.
self.picker = sender;
__block id weakSelf = self;
// Note: Instead of `id` you could specify the class of `self` order to access properties with dot notation.
// Dismiss the WSAssetPickerController.
[self dismissViewControllerAnimated:YES completion:^{
// Do something with the assets here.
// Release the picker.
[weakSelf setPicker:nil];
}];
}
An alternative would be to process the array of ALAssets before calling dismissViewControllerAnimated:completion:, but that could cause the picker controller's dismissal to delay resulting in a poor user experience.
i want to create an application in one row of tableView there will be 4 images of button which will be loaded from server in background because if i directly load them than the table view will hang some. for this i have used this code for creating button in cell and performing to download images in background.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *hlCellID = #"hlCellID";
UITableViewCell *hlcell = [tableView dequeueReusableCellWithIdentifier:hlCellID];
if(hlcell == nil) {
hlcell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:hlCellID] autorelease];
hlcell.accessoryType = UITableViewCellAccessoryNone;
hlcell.selectionStyle = UITableViewCellSelectionStyleNone;
}
int section = indexPath.section;
NSMutableArray *sectionItems = [sections objectAtIndex:section];
int n = [sectionItems count];
int i = 0, j = 0, tag = 1;
int x = 10;
int y = 30;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (i = 1; i<= n ; i++) //[arr count]
{
for(j=1; j<=4;j++)
{
if (i>=n) break;
Item *item = [sectionItems objectAtIndex:i];
CGRect rect = CGRectMake(x = x, y = y, 68, 65);
UIButton *button=[[UIButton alloc] initWithFrame:rect];
[button setFrame:rect];
UIImage *buttonImageNormal=[UIImage imageNamed:item.image];
[button setBackgroundImage:buttonImageNormal forState:UIControlStateNormal];
[button setContentMode:UIViewContentModeCenter];
// set the image to be loaded (using the same one here but could/would be different)
NSURL *imgURL = [NSURL URLWithString:#"http://londonwebdev.com/wp-content/uploads/2010/07/featured_home.png"];
// Create an array with the URL and imageView tag to
// reference the correct imageView in background thread.
NSMutableArray *arr = [[NSArray alloc] initWithObjects:imgURL, [NSString stringWithFormat:#"%d", tag], nil ];
// Start a background thread by calling method to load the image
[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:arr];
// button.tag = [tagValue intValue];
button.tag = tag;
//NSLog(#"....tag....%d", button.tag);
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[hlcell.contentView addSubview:button];
[button release];
tag++;
x = x + 77;
}
x = 10;
y = y + 74;
}
[pool release];
return hlcell;
}
the above code work perfectly but when i download the images and trying to assign at the some particular button than i can't find the button tags althoug i can find the button tags while touchupinside action.
- (void) loadImageInBackground:(NSArray *)urlAndTagReference {
NSLog(#"Received URL for tagID: %#", urlAndTagReference);
// Create a pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Retrieve the remote image. Retrieve the imgURL from the passed in array
NSData *imgData = [NSData dataWithContentsOfURL:[urlAndTagReference objectAtIndex:0]];
UIImage *img = [[UIImage alloc] initWithData:imgData];
// Create an array with the URL and imageView tag to
// reference the correct imageView in background thread.
NSMutableArray *arr = [[NSArray alloc] initWithObjects:img, [urlAndTagReference objectAtIndex:1], nil ];
// Image retrieved, call main thread method to update image, passing it the downloaded UIImage
[self performSelectorOnMainThread:#selector(assignImageToImageView:) withObject:arr waitUntilDone:YES];
[pool release];
}
- (void) assignImageToImageView:(NSArray *)imgAndTagReference
{
// Create a pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i;
UIButton *checkView;
// [imagesForCategories addObject:[imgAndTagReference objectAtIndex:1]];
// UITableViewCell *cell = [celebCategoryTableView cellForRowAtIndexPath:[imgAndTagReference objectAtIndex:1]];
// UIImageView *profilePic = (UIImageView *)[cell.contentView viewWithTag:20];
// profilePic.image = [imgAndTagReference objectAtIndex:0];
// checkView.tag = [[imgAndTagReference objectAtIndex:1] intValue];
// loop
for (UIButton *checkView in [self.tblImage subviews] )
{ i++;
NSLog(#"Checking tag: %d against passed in tag %d",checkView.tag, [[imgAndTagReference objectAtIndex:1] intValue]);
if ([checkView tag] == [[imgAndTagReference objectAtIndex:1] intValue]) {
if (i==35) break;
// Found imageView from tag, update with img
// [checkView setImage:[imgAndTagReference objectAtIndex:0]];
[checkView setImage:[imgAndTagReference objectAtIndex:0] forState:UIControlStateNormal];
//set contentMode to scale aspect to fit
checkView.contentMode = UIViewContentModeScaleAspectFit;
//change width of frame
CGRect frame = checkView.frame;
frame.size.width = 80;
checkView.frame = frame;
}
}
// release the pool
[pool release];
// Remove the activity indicator created in ViewDidLoad()
[self.activityIndicator removeFromSuperview];
}
the all code works perfect but i can't find the table cell subview here for (UIButton *checkView in [self.tblImage subviews] so how to find the subviews of table cell subviews.?
i want to create something like this pls see image.! after that new city will come and just section change the data will show new images in row and cell section.
you may use SDWebImage
Web Image
This library provides a category for UIImageVIew with support for remote images coming from the web.
It provides:
An UIImageView category adding web image and cache management to the Cocoa Touch framework
An asynchronous image downloader
An asynchronous memory + disk image caching with automatic cache expiration handling
A guarantee that the same URL won't be downloaded several times
A guarantee that bogus URLs won't be retried again and again
Performances!
just use it
[youImageView setImageWithURL:[NSURL URLWithString:url] placeholderImage:nil options:SDWebImageRetryFailed];
I am building an App where the user can spin a UIPickerView like a slot machine. The problem I am facing at the moment that at runtime the images in my pickerView start disappearing at random. Then spin again and some of them are back.
Here is the code I use to make the array of images (in my project there are 17 images in every array but to save a bit of space I narrowed it down):
- (void)viewDidLoad{
[super viewDidLoad];
[drinkPickerView_ selectRow:1000 inComponent:0 animated:NO];
[drinkPickerView_ selectRow:1000 inComponent:1 animated:NO];
[drinkPickerView_ selectRow:1000 inComponent:2 animated:NO];
if (managedObjectContext_ == nil)
{
managedObjectContext_ = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
drinkPickerView_.delegate = self;
drinkPickerView_.dataSource = self;
UIImage *fris1 = [UIImage imageNamed:#"fris01.PNG"];
UIImage *fris2 = [UIImage imageNamed:#"fris02.PNG"];
UIImage *fris3 = [UIImage imageNamed:#"fris03.PNG"];
UIImage *fris4 = [UIImage imageNamed:#"fris04.PNG"];
UIImage *fris5 = [UIImage imageNamed:#"fris05.PNG"];
UIImageView *frisView1 = [[UIImageView alloc]initWithImage:fris1];
UIImageView *frisView2 = [[UIImageView alloc]initWithImage:fris2];
UIImageView *frisView3 = [[UIImageView alloc]initWithImage:fris3];
UIImageView *frisView4 = [[UIImageView alloc]initWithImage:fris4];
UIImageView *frisView5 = [[UIImageView alloc]initWithImage:fris5];
UIImage *alcoholisch1 = [UIImage imageNamed:#"alcohol01.PNG"];
UIImage *alcoholisch2 = [UIImage imageNamed:#"alcohol02.PNG"];
UIImage *alcoholisch3 = [UIImage imageNamed:#"alcohol03.PNG"];
UIImage *alcoholisch4 = [UIImage imageNamed:#"alcohol04.PNG"];
UIImage *alcoholisch5 = [UIImage imageNamed:#"alcohol05.PNG"];
UIImageView *alcoholischView1 = [[UIImageView alloc]initWithImage:alcoholisch1];
UIImageView *alcoholischView2 = [[UIImageView alloc]initWithImage:alcoholisch2];
UIImageView *alcoholischView3 = [[UIImageView alloc]initWithImage:alcoholisch3];
UIImageView *alcoholischView4 = [[UIImageView alloc]initWithImage:alcoholisch4];
UIImageView *alcoholischView5 = [[UIImageView alloc]initWithImage:alcoholisch5];
UIImage *freaky1 = [UIImage imageNamed:#"freaky01.PNG"];
UIImage *freaky2 = [UIImage imageNamed:#"freaky02.PNG"];
UIImage *freaky3 = [UIImage imageNamed:#"freaky03.PNG"];
UIImage *freaky4 = [UIImage imageNamed:#"freaky04.PNG"];
UIImage *freaky5 = [UIImage imageNamed:#"freaky05.PNG"];
UIImageView *freakyView1 = [[UIImageView alloc]initWithImage:freaky1];
UIImageView *freakyView2 = [[UIImageView alloc]initWithImage:freaky2];
UIImageView *freakyView3 = [[UIImageView alloc]initWithImage:freaky3];
UIImageView *freakyView4 = [[UIImageView alloc]initWithImage:freaky4];
UIImageView *freakyView5 = [[UIImageView alloc]initWithImage:freaky5];
NSArray *frisImageArray = [[NSArray alloc]initWithObjects:frisView1,frisView2,frisView3,frisView4,frisView5, nil];
NSArray *alcoholischImageArray = [[NSArray alloc]initWithObjects:alcoholischView1,alcoholischView2,alcoholischView3,alcoholischView4,alcoholischView5, nil];
NSArray *freakyImageArray = [[NSArray alloc]initWithObjects:freakyView1,freakyView2,freakyView3,freakyView4,freakyView5, nil];
NSString *frisFieldName = [[NSString alloc]initWithFormat:#"frisDrankenPlaatjesArray"];
[self setValue:frisImageArray forKey:frisFieldName];
NSString *alcoholischFieldName = [[NSString alloc]initWithFormat:#"alcoholischeDrankenPlaatjesArray"];
[self setValue:alcoholischImageArray forKey:alcoholischFieldName];
NSString *freakyFieldName = [[NSString alloc]initWithFormat:#"freakyDrankenPlaatjesArray"];
[self setValue:freakyImageArray forKey:freakyFieldName];
}
This is the code where I load the images in the pickerView:
-(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row
forComponent:(NSInteger)component reusingView:(UIView *)view{
if (component==0) {
NSString *arrayName = [[NSString alloc]initWithFormat:#"alcoholischeDrankenPlaatjesArray"];
NSArray *array = [self valueForKey:arrayName];
return [array objectAtIndex:(row%5)];
}
else if(component==1){
NSString *arrayName = [[NSString alloc]initWithFormat:#"frisDrankenPlaatjesArray"];
NSArray *array = [self valueForKey:arrayName];
return [array objectAtIndex:(row%5)];
}
else if (component==2){
NSString *arrayName = [[NSString alloc]initWithFormat:#"freakyDrankenPlaatjesArray"];
NSArray *array = [self valueForKey:arrayName];
return [array objectAtIndex:(row%5)];
}
else{
return nil;
}
}
this is the code that makes the pickerView spin:
-(IBAction)rotate:(id)sender{
int numInRow =1;
int lastVal = -1;
for (int i=0;i<3; i++) {
int newValue = arc4random()%1000;
if (newValue==lastVal)
numInRow++;
else
numInRow =1;
lastVal=newValue;
[drinkPickerView_ selectRow:newValue inComponent:i animated:YES];
[drinkPickerView_ reloadComponent:i];
}
}
I hope this is enough information and I hope somebody can help me out.
I had a similar problem. I tried retaining the objects, arrays, images but that didn't fix it. Turns out that if I populated the arrays again (ala how you initialized them in the viewDidLoad method) in the -pickerView viewForRow: method then it worked great. Seems inefficient to repopulate the same arrays with every method call but it seemed to do the trick.
I think the problem lays at where you initialize your UIImages:
UIImage *fris1 = [UIImage imageNamed:#"fris01.PNG"]; <-- this is autorelease!
You need to set your UIImages as properties so that they can be retained.
Like so:
#property (nonatomic,retain) UIImage *fris1;
and synthesize them in your .m. and applying the image as:
self.fris1 = [UIImage imageNamed:#"fris01.PNG"];
This way, the UIImage is retained throughout the app life.
This is from UIPickerView.h.
/*
these methods return either a plain UIString, or a view (e.g UILabel) to display the row for the component. for the view versions, we cache any hidden and thus unused views and pass them back for reuse. If you return back a different object, the old one will be released. the view will be centered in the row rect
*/
(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component;
(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view;
So when your pickerview tries to show a previously shown uiimageview it releases the previous one. That's why you should create different uiimageview for each component.