-(IBAction)actionPrevious:(id)sender{
[self startact];
pageNumber = pageNumber - 1;
if (pageNumber>0) {
NSString *str_Img =[array_Image objectAtIndex:pageNumber];
NSData *mydata = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:str_Img]];
UIImage *myimage = [[UIImage alloc] initWithData:mydata];
[imageView1 setImage:myimage];
[self.view addSubview:imageView1];
lbl_PhotoName.text = [array_Name objectAtIndex:pageNumber];
lbl_PhotoDate.text = [array_Date objectAtIndex:pageNumber];
lbl_PhotoDesc.text = [array_Desc objectAtIndex:pageNumber];
[mydata release];
[myimage release];
}
[self endact];
}
-(void)startact{
[act setHidden:NO];
[act startAnimating];
}
-(void)endact{
[act stopAnimating];
[act setHidden:YES];
}
In above code activity activity indicator is not display. Photo are display using the web service. please Help!
Thank You
You need to work on the same thread and need to call by this way
[self performSelector:#selector(startact) withObject:nil afterDelay:1];
You need to use threading in these kinds of scenarios.
Because activity indicator is on same thread as of the images work; thats why it is creating problem.
This is a silly mistake that I always seem to make: If you added the activity indicator programmatically did you make sure to addSubview: ? Or maybe it's hidden by something? Everything else looks fine, and you definitely don't need to startAnimating in a separate thread.
Related
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;
Dear stackoverflowers,
I have gone astray.
In my app I load 2 images from the web, like this:
-(void)loadImages
{
...
image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:imgUrl1]];
image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:imgUrl2]];
}
In order to not blocking the main thread, I use GCD:
dispatch_async( dispatch_get_global_queue(0,0), ^{
[self loadImages];
After that, I use these images in my UITableView:
if (indexPath.row == 0)
{
cell.imageView.image = image1;
}
else
{
cell.imageView.image = image2;
}
Then I decided to add UIActivityIndicator, but faced some problems. I understand that my code is not correct. I saw that people using NSURLRequest and NSURLConnection to load images and add UIActivityIndicator.
Could you tell me please, what is the most standart way to load images like that ? What should I rewrite ?
I would suggest you to use AsyncImageView a beautiful implementation by Nicklockwood -father of iCarousel.
https://github.com/nicklockwood/AsyncImageView
it is very simple to use.
#import "AsyncImageView.h"
and in all imageViews do this.
[imageView setImage:#"default.png"];
[imageView setImageURL:#"whateverurl/whateverimage.png"];
In your case it would be:
[cell.imageView setImageURL:#"yourURL"];
It works like a charm, and my code is in production. But if you still want your code to work try this:
UIActivityIndicator *activity =[[UIActivityIndicator alloc] initWithStyle:UIActivityIndicatorWhite];
[activity setFrame:CGRectMake(100,100,30,30)];
[self.view addSubview:activity];
dispatch_queue_t dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(dispatchQueue, ^(void)
{
[activity startAnimating];
[self loadImages];
dispatch_sync(dispatch_get_main_queue(), ^{
[yourTableView reloadData];
[activity stopAnimating];
[activty setHidden:YES];
});
});
I can tell you what I usually do if I want to use my own custom code
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData * imageData = [NSData dataWithContentsOfURL:_pictureURL];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:imageData];
});
});
Otherwise you can consider the UIImageView+AFNetworking category that adds the method
setImageWithURLRequest:placeholderImage:success:failure:
to UIImageView.
There is nothing wrong with your code (assuming that you've confirmed that it works). Just because others use NSURLConnection and related doesn't make yours wrong.
To use the activity indicator do this:
-(void)loadImages
{
UIActivityIndicator *indicator = ...
...
[indicator startAnimating];
image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:imgUrl1]];
image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:imgUrl2]];
[indicator stopAnimating];
}
Small nit - personally I'd use:
cell.imageView.image = (0 == indexPath.row ? image1 : image2)
as nobody seems to appreciate the C 'conditional expressoin'. End small nit.
This is written in my viewDidLoad method
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *op = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(downloadImage)
object:nil];
[queue addOperation:op];
// The the rest in other methods;
- (void)downloadImage{
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:person.picURL]];
UIImage* image = [[UIImage alloc] initWithData:imageData] ;
[self showImage: image];
}
I have tried adding the following codes above [self showImage: image]; and i ended up with an exception.
1.) [self performSelectorOnMainThread:#selector(showImage:) withObject:image waitUntilDone:NO];
2.) [self performSelectorInBackground:#selector(showImage:) withObject:image];
// This is the showImage code.
- (void)showImage:(UIImage *)img {
if (img != nil)
{
myImageView = [[UIImageView alloc] initWithImage:img];
myImageView.frame = CGRectMake(20, 20, 132, 124);
[scrollView addSubview:myImageView];
[pictureOfPerson setImage:img];
}
}
I am trying to Asynchronously download the image and cache it. The image gets downloaded Asynchronously but i am not sure if it gets cached.
1.) How to cache the image and use it in when the view loads again
2.) While the image is downloading, what if i click on another view. Then i need to stop the download. How can i write this code. I know that i have to write it in the viewDidDissapear method.
3.) Is my code correct. Have i missed anything or is there a better approach to do this? if so tutorial or some sample code please
I'd use GCD to download the image. It's much simpler to use than NSOperation. Here's an example:
UIImage *personPicture;
personPicture = [self.imageCache objectForKey:person.picURL];
if (!personPicture) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:person.picURL]];
personPicture = [UIImage imageWithData:imageData];
[self.imageCache setObject:imageData forKey:person.picURL];
dispatch_async(dispatch_get_main_queue(), ^{
[self showImage:personPicture];
});
});
}
else {
[self showImage:personPicture];
}
You could use a class property like an NSMutableDictionary to store the UIImage data and associate it with your URL. If it's present, use it, if not, download the image.
-EDIT-
Adding the code to handle caching.
You can use this:SDWebImage
I have a refresh button on my navigationbar
buttonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:#selector(buttonItemClicked)];
self.navigationItem.rightBarButtonItem = buttonItem;
-(void)buttonItemClicked{
NSLog(#"buttonItemclicked");
myView.labelName.text = nil;
myView.otherLabelName.text = nil;
[spinner startAnimating]
[spinnerView setHidden:NO];
[self requestAPI];
[spinner stopAnimating];
[spinnerView setHidden:YES];
}
If I go in and out of the view, it works fine. But when I call the same methods in buttonItemClicked, it doesn´t work. I also tried calling the view methods inside my action method, but that doesn´t work either.
What I´m trying to do is set my labels to nil, add my UIActivityIndicatorView and remove it after the labels are set again.
I have already tried [self.view setNeedsDisplay];
The refresh it self works, but the animations doesn´t work.
Any suggestions?
The animation is not working because you call startAnimating and stopAnimating (and setHidden) in the same method.
The render start at the end of the method call.
You need to set
[spinner stopAnimating];
[spinnerView setHidden:YES];
in requestAPI.
Edit:
Using Grand Central Dispatch. Like:
- (void)buttonItemClicked {
myView.labelName.text = nil;
myView.otherLabelName.text = nil;
[spinner startAnimating]
[spinnerView setHidden:NO];
[self requestAPI];
}
- (void)requestAPI {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSURL *url = [NSURL URLWithString:#"http://example.com"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSString *stringResult = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
[spinnerView setHidden:YES];
myView.labelName.text = stringResult;
});
});
}
Try [myView setsNeedToDisplay];.
I have a refresh button on my navigationbar
buttonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:#selector(buttonItemClicked)];
self.navigationItem.rightBarButtonItem = buttonItem;
-(void)buttonItemClicked{
NSLog(#"buttonItemclicked");
myView.labelName.text = nil;
myView.otherLabelName.text = nil;
[spinner startAnimating]
[spinnerView setHidden:NO];
[self requestAPI];
[spinner stopAnimating];
[spinnerView setHidden:YES];
}
If I go in and out of the view, it works fine. But when I call the same methods in buttonItemClicked, it doesn´t work. I also tried calling the view methods inside my action method, but that doesn´t work either.
What I´m trying to do is set my labels to nil, add my UIActivityIndicatorView and remove it after the labels are set again.
I have already tried [self.view setNeedsDisplay];
The refresh it self works, but the animations doesn´t work.
Any suggestions?
The animation is not working because you call startAnimating and stopAnimating (and setHidden) in the same method.
The render start at the end of the method call.
You need to set
[spinner stopAnimating];
[spinnerView setHidden:YES];
in requestAPI.
Edit:
Using Grand Central Dispatch. Like:
- (void)buttonItemClicked {
myView.labelName.text = nil;
myView.otherLabelName.text = nil;
[spinner startAnimating]
[spinnerView setHidden:NO];
[self requestAPI];
}
- (void)requestAPI {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSURL *url = [NSURL URLWithString:#"http://example.com"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSString *stringResult = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
[spinnerView setHidden:YES];
myView.labelName.text = stringResult;
});
});
}
Try [myView setsNeedToDisplay];.