I need to add an activityIndicator to a UIView.I have a button,when that button is clicked then it has to start animating. Actually when the button is clicked some data is received from rest service and parsing is done and then it is filled in UITableView.But the activity indicator is not getting animating..
- (void)viewDidLoad
{
[super viewDidLoad];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc]
initWithFrame:CGRectMake(0.0f, 0.0f, 20.0f, 20.0f)];
[activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview:activityIndicator];
}
-(IBAction)switchtoGetProviders
{
[activityIndicator startAnimating];
NSURL *urlString= [NSString stringWithFormat:#"http://230.32.232.32/services/service.svc/Xml"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc] init]autorelease];
..............//calling data from service url
}
After reciving the whole data it is assigned to UITableView.
How can I get it working ?
You can't start and stop activity indicator in one single function/method.
There are two methods to do this things.
If the request is Asynchronous then you need to start activity indicator at button click and stop when you receive response.
But if the request is synchronous then it is not possible to start and stop activity in one function.for this you need to start animation on button click and make separate method for send synchronous request and call that method using [self performSelector:] method. At the end you need to stop animating.
Updates:
-(IBAction)switchtoGetProviders
{
[activityIndicator startAnimating];
[self performSelector:#selector(startRequest) withObject:nil afterDelay:0];
}
- (void)startRequest
{
NSURL *urlString= [NSString stringWithFormat:#"http://230.32.232.32/services/service.svc/Xml"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc] init]autorelease];
..............//calling data from service url
[activityIndicator stopAnimating];
}
Probably this is due to the fact that you are making the webservice call and updating the UI at the same time on MAIN Thread. You must use GCD or detach another thread for making the webservice call.
Use this to detach a new thread
[NSThread detachNewThreadSelector:#selector(callWebserviceMethod:) toTarget:self withObject:nil];
In your code
-(IBAction)switchtoGetProviders
{
[activityIndicator startAnimating];
[NSThread detachNewThreadSelector:#selector(callWebserviceMethod:) toTarget:self withObject:nil];
}
-(void)callWebserviceMethod
{
NSURL *urlString= [NSString stringWithFormat:#"http://230.32.232.32/services/service.svc/Xml"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc] init]autorelease];
}
You should define activityIndicator as a property, in your code you have it as a local variable.
After defining it as a property, change the assignment line to:
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 20.0f, 20.0f)];
you need to get data from web service in background thread, as calling it on the main thread causes the UI to hang
see this
You have declared the UIActivityIndicatorView *activityIndicator in viewDidLoad method so it is local object only visible to this function you need to declare it in the header file or in class category in .m. When you declare the activityIndicator instance in the .h then you will be able to access this within your class. Either you can make it as property or just declare in .h then initialize in your viewDidLoad method without redeclaration.
just add this line in .h file
UIActivityIndicatorView *spinningWheel;
and in viewWillAppear method add this code..
spinningWheel = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(120, 200, 25.0, 25.0)];
spinningWheel.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;///UIActivityIndicatorViewStyleGray also use this if background white
[self.view addSubview:spinningWheel];
-(IBAction)switchtoGetProviders
{
[spinningWheel startAnimating];
NSURL *urlString= [NSString stringWithFormat:#"http://230.32.232.32/services/service.svc/Xml"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc] init]autorelease];
..............//calling data from service url
}
and when you get data or response at that time stopAnimating like bellow..
[spinningWheel stopAnimating];
Just do one this , declare it in .h file mean declare glibly
.h
#interface yourViewController : UIViewController
{
IBOutlet UIActivityIndicatorView *activityIndicator;
}
.m
- (void)viewDidLoad
{
[super viewDidLoad];
activityIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
activityIndicator.color = [UIColor blackColor];
[self.view addSubview:activityIndicator];
}
-(IBAction)switchtoGetProviders
{
[activityIndicator startAnimating];
NSURL *urlString= [NSString stringWithFormat:#"http://230.32.232.32/services/service.svc/Xml"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc] init]autorelease];
..............//calling data from service url
}
Related
So for my application, I add a view (aView) on top of my current view (classesWebView) as a Subview. All the aView is, is a UIView with a UIActivityIndicatorView on top of it that is supposed to animate while the view underneath (classesWebView) loads the appropriate Web Page.
I can see that the classesWebView webpage does appear (aView has an alpha of .5), but as soon as it finishes loading all the way, aView is sent [aView removeFromSuperview] and it disappears but after it goes away, all that's left is a white screen in it's place.
I have done this for two other methods and I don't know why, on only this method, it refuses to cooperate.
Any suggestions would be appreciated. The App is for iOS 6.
viewDidLoad method:
-(void)viewDidLoad
{
[super viewDidLoad];
classesWebView.delegate = self;
[classesWebView addSubview:aView];
NSURL *class = [NSURL URLWithString:#"mywebistelink"];
NSURLRequest *classRequest = [NSURLRequest requestWithURL:class];
[classesWebView loadRequest:classRequest];
}
webViewDidStartLoad method:
preView and switchView are Activity Indicators.
- (void)webViewDidStartLoad:(UIWebView *) webview
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
if(aView.superview != nil)
{
[preView startAnimating];
}
else
{
[switchView startAnimating];
}
}
webViewDidFinishLoad method:
- (void)webViewDidFinishLoad:(UIWebView *) webview
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if(aView.superview != nil)
{
[aView removeFromSuperview];
[preView stopAnimating];
[preView setOpaque:false];
}
else
{
[switchView stopAnimating];
[switchView setOpaque:false];
}
}
[Further clarity: The reason I have the if-statement, is because I want another indicator for the classesWebView when loading pages but I do NOT want it to appear unless aView is gone (since aView already has it's on indicator: preView)]
EDIT: Just to prove that it is ONLY THE removeFromSuperview that is causing the problem, if I call [aView setAlpha:0.0] it disappears and the webPage below it loads properly. But the second that I call [aView removeFromSuperview] the web page turns into a white screen. T_T
try this:
NSURL *class=[NSURL URLWithString:[yourwebistelink stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *request=[NSURLRequest requestWithURL:class];
[self.classesWebView loadRequest:request];
try this one.. and try to dont add aView for activityIndicator., try this this one for indicating activityIndicator
UIWebView * classesWebView = [[UIWebView alloc] init];
[classesWebView addSubview:activityIndicator];
[self.activityIndicator startAnimating]; //for activityIndicator
NSURLRequest *request = [NSURLRequest requestWithURL:weburl];
classesWebView.frame = CGRectMake(0, 200, 768, 400);
[classesWebView setScalesPageToFit:NO];
[classesWebView loadRequest:request];
- (void)webViewDidStartLoad:(UIWebView *)thisWebView
{
}
- (void)webViewDidFinishLoad:(UIWebView *)thisWebView
{
[self.activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
NSLog(#"Error : %#",error);
}
if still webView is displaying blank white, then you have to encode your url by this one
NSString *encodedString=[graphStringUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *weburl = [NSURL URLWithString:encodedString];
NSURLRequest *request = [NSURLRequest requestWithURL:weburl];
then load this request in webView
[classesWebView loadRequest:request];
I don't think you should be adding subviews to a UIWebView. Try adding aView to the view that contains your classesWebView and see if that fixes the problem.
So I never got it to work but I cheated it by just setting [aView setAlpha:0]. That worked for what I needed. Thanks for the suggestions though, guys.
I am using a scrollview to display a viewcontrollers view. if the user reaches the end of the cached views my method reloads the new views. My NSLogs say that the method is finished but it takes additional 5 seconds to display the view.
I think that the [scrollView addSubview:vc.view] is very very slow but I found nothing to improve it.
the whole method gets called in -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
scrollView.userInteractionEnabled = NO;
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[activityIndicator setFrame:CGRectMake((320.f*index)+135.f, 151, 50, 50)];
[activityIndicator setHidesWhenStopped:YES];
[activityIndicator startAnimating];
[scrollView addSubview:activityIndicator];
MBBAppDelegate *delegate = (MBBAppDelegate *)[UIApplication sharedApplication].delegate;
[delegate fetchDealsWithFilter:dealFilter fromIndex:index toIndex:(index+3) onSuccess:^(id object){
MBBDealList *list = object;
int i = 0;
ProductDetailViewController *vc;
for (MBBDeal *deal in [list deals]) {
NSLog(#"start %i",i);
int indexInArray = i;//[list.deals indexOfObject:deal];
if (indexInArray+index >= numDeals) {
return;
}
vc = [[ProductDetailViewController alloc] init];
//fetch the deal and insert
vc.numberOfDeals = numDeals;
vc.dealIndex = index+1+indexInArray;
vc.dealFilter = dealFilter;
vc.deal = deal;
vc.view.frame = CGRectMake(320.f*(index+indexInArray), 0.f, 320.f, 436.f);
[scrollView addSubview:vc.view];
[productDetailViewControllers insertObject:vc atIndex:(index+indexInArray)];
i++;
}
[activityIndicator stopAnimating];
scrollView.userInteractionEnabled = YES;
}];
}
Does anyone know how I can improve my method?
What I can understand from your problem is that, the activity indicator that you have used to show the data fetch process is not used properly.
You data fetch process is still working, even after the activity indicator disappears.
You can do 2 things for that:
ether call the data fetch method in background using performSelectorInBackground method or place the activity indicator in the app delegate where you have created your data fetch method.
I want to display UIActivityIndicatorView over splash screen.
I'm just creating a splashView and activityindicator over splashview in AppDelegate.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//[NSThread sleepForTimeInterval:3];
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
splashView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
UIImage *splashImage = [UIImage imageNamed:#"Splashimage.png"];
splashImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
splashImageView.image = splashImage;
[splashView addSubview:splashImageView];
progressIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(145,440,30,30)];
progressIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite;
[progressIndicator startAnimating];
[splashView addSubview:progressIndicator];
[self.window addSubview:splashView];
[NSThread detachNewThreadSelector:#selector(getInitialData:)
toTarget:self withObject:nil];
[self.window makeKeyAndVisible];
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
return YES;
}
- (void)getInitialData:(id)obj {
[NSThread sleepForTimeInterval:3.0];
[splashView removeFromSuperview];
[window addSubview:viewController.view];
}
It is working fine except memory leakage.
I'm getting message in console that autoreleased with no pool in place - just leaking.
What i m doing wrong?
Any help will be appreciated.
You don't seem to be releasing anything here.
Your thread method getInitialData must create and drain an autorelease pool. This is done automatically for the main thread but not for any extra threads that you create. Just add this at the top of the method:
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
and this at the bottom:
[localpool drain];
The reason that you are getting the error message is because viewController.view is returning an autoreleased object and you don't have an autorelease pool in place on the thread.
There's a couple problems here. You need to release anything you alloc. The variables splashview, splashImageView, and progressIndicator are allocated but not released, so those will leak.
The message you are getting about the NSAutoreleasePool is because you are doing getInitialData: on a separate thread. NSAutoreleasePools are per-thread, so you you need to do this:
-(void)getInitialData:(id)obj {
NSAutoreleasePool pool = [NSAutoreleasePool new];
[NSThread sleepForTimeInterval:3.0];
[splashView removeFromSuperview];
[window addSubview:viewController.view];
[pool release];
}
Do you really need to make as ivar/properties ?
UIActivityIndicatorView* progressIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(145,440,30,30)];
progressIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite;
[progressIndicator startAnimating];
[splashView addSubview:progressIndicator];
[progressIndicator release]; // release
[self.window addSubview:splashView];
[splashView release]; // release
The following line is not none of my business:
I do not know, but first time i am seeing that some one is adding the
activity indicator on splash image. and why do you need to have
splashImageView, you could have directly make an entry in your plist
file for LaunchImage key entry
-(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.
I have a viewcontroller that repeatedly repositions 6 items within a uiscrollview. However, even though I've limited the number of items within the uiscrollview to 6, I'm still leaking memory when i update their position and their image. Can someone let me know if the following code which represents a unit within the uiscrollview is properly coded? startLoad is the method that I call after to reload the image.
#import "ScrollUnit.h"
#implementation ScrollUnit
#synthesize index;
#synthesize ProductToDisplay;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
}
return self;
}
-(void)startLoad
{
[imageview removeFromSuperview];
[imageview release];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage)
object:nil];
[queue addOperation:operation];
[operation release];
}
-(void)loadImage
{
NSString *myimageName = [self.ProductToDisplay valueForKey:IMAGEKEY];
NSString *myimageUrl = [NSString stringWithFormat:#"%#/%#",IMAGE_SERVICE,myimageName];
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:myimageUrl]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
- (void)displayImage:(UIImage *)image
{
imageview = [[[UIImageView alloc] initWithFrame:CGRectMake(9, 0, 320, 320)]retain];
imageview.contentMode = UIViewContentModeScaleAspectFit;
imageview.backgroundColor = [UIColor whiteColor];
imageview.image = image;
[self addSubview:imageview];
[imageview release];
//[image release];
}
- (void)dealloc {
[super dealloc];
}
#end
Get rid of the retain message on this line and you should be all set:
imageview = [[[UIImageView alloc] initWithFrame:CGRectMake(9, 0, 320, 320)]retain];
The reason why you need to do this is because you already own the object by calling alloc, so at that point, the relative reference count is 2.
Once you invoke addSubview:, passing in the imageview, the reference count gets bumped to 3, then right back down to 2 once you release it on the next line.
So once that object gets sent release in -dealloc, you're still stuck because the reference count is now 1, not 0 as you expected.
There is also another little thing that might bug (or not). You don't release imageview before you assign it in displayImage method. As long as only startLoad is called you are fine but if displayImage is called from the outside then you still leak.
You might want to use a property with retain and then synthesis the getter and setter methods. This way the iOS will release your previous assignment before it retains your new assigned object. That said then you need to release created image view right were you create it and you have to use "self.imageview" in order to make sure that you use the setter (setImageview).