iPhone: Loading data with a progress animation? - iphone

I'm creating an iPhone app and am wondering how to have a progress animation when you're loading data? I see this a lot in applications such as Tweetie, but haven't been able to figure it out myself.

If you are talking about loading data over a network, ASIHTTPRequest provides a way to pass a reference to a UIProgressView that it will update with accurate progress for both downloads and uploads. I highly recommend it.

If you only want the small network spinner in the statusbar you activate it with
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
...and deactivate
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

In an app I wrote for our company that performs a very long sync (by accessing a web service), I display an UIActivityIndicatorView.
On the same view, I also included a label that displays "Fetching X of Y..." The label is updated via an NSTimer. The call looks like:
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(updateLabel:) userInfo:nil repeats:YES];
In addition, in order for the UI to actually update, I had to spin off the code to fetch data from the webservice into its own thread.

Do you mean a progress bar, or an activity indicator? For an occurring activity, you can use UIActivityIndicatorView.
The flow will look a little like this.
UIActivityIndivatorView *activity = [[UIActivityIndivatorView alloc] init];
//attach activity to a view or a bar
//begin activity
[activity startAnimating];
//here will be the functionality for your data gathering progress
//once your progress or activity is done
[activity stopAnimating];
Hope this helps.

Related

Loading plist on launch takes long. How to show activity indicator?

My app is loading an online plist on launch, which is needed to display the data in the tableview which will be shown. Depending on the internet connection, loading the plist can take rather long (4-5 seconds) and the launch screen is shown this entire time. Now, I'd like to put an activity indicator in the status bar (while launch screen is still up) so that the user knows the app is busy loading.
I'm loading the plist and creating arrays etc. in ViewDidLoad, and I'm not sure on how to achieve what I've sketched above.
Do you have any thoughts on this matter? Thanks.
I would reconsider your approach if I were you. Unless you've specifically put in measures to avoid it, it's likely that your code to download the plist will be being called before applicationDidFinishLaunching: returns. This is not good because if it takes a long time then the watchdog might kill your app even before it's actually properly launched. Not a good thing.
You should really be kicking off the download in a background thread and just stick a spinner in your actual view. So something like this:
- (void)viewDidLoad {
...
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(self.view.bounds.size.width / 2.0f, self.view.bounds.size.height / 2.0f);
[spinner startAnimating];
[self.view addSubview:spinner];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do your downloading of your plist, etc
dispatch_async(dispatch_get_main_queue(), ^{
[spinner removeFromSuperview];
});
});
}

Problem with MBProgressHUD while loading images from server

I have a server that provides a JSON with certain parameters and the name of an image. Then I get the image with the name provided. All this is done in one function called loadingOfImageAndInformation. I use the MBProgressHUD as follows:
[HUD showWhileExecuting:#selector(loadingOfImageAndInformation)
onTarget:self withObject:nil animated:YES];
Which should show the progress thingy when this method is currently running. Now, inside the method I use a ASIHTTPRequest to retrieve all the data I need. Which means that sometime it will jump from that method to the request methods (to retrieve the image and assign it to the UIImageView on the requestLoadDone).
Now, the problem is that the MBProgressHUD thingy only shows until the parameters are shown (the image description I put on a label, the description I got from JSON) and not until the parameters AND image are shown. So basically the loader disappears BEFORE the image is on the imageView.
This is the code in question:
- (void) loadingHudAlert {
NSString *loadingMessage = NSLocalizedString(#"Please Wait",
#"Message displayed when the loading spinner is on");
HUD = [[MBProgressHUD alloc] initWithView:self.view];
HUD.minShowTime = 1.0;
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = loadingMessage;
[HUD showWhileExecuting:#selector(loadingOfImageAndInformation)
onTarget:self withObject:nil animated:YES];
}
The ASIHTTPRequest does all request on an asynchronous mode. Without a queue.
Thank you for your feedback!!!!
I solved it using a boolean, if the method requestLoadDone is finished the bool turns to be NO and while the boolean is YES the loadingOfImageAndInformation will run (which means will run until the image is correctly retrieved.) I haven't posted this as an answer since maybe someone has a better solution.
So you're saying that the HUD disappears before the image is shown at your imageview, don't you? Maybe this is more due to how cocoa processes this stuff than MBProgressHUD problem.
How are you assigning the image? Have you tried?
[yourimageview setNeedsDisplay];
What I'm trying to say is that, if this is how cocoa manages the imageviews showing stuff, maybe you can try to "force" the reload or displaying to be done before.

Yet another question about showing UIActivityIndicator

I had the UIActivityIndicatorView working fine in simulator and other 3.0 devices in my app. But I found out that it was not spinning (or showing) in the new iphone 4. Basically I need to show the activity indicator when a button is clicked and hide it when the button click event is complete. I was using the approach below.
[NSThread detachNewThreadSelector: #selector(spinBegin) toTarget:self withObject:nil];
from this link. As mentioned, it correctly spins the activity indicator on all except 4.*.. not sure why. To get around this, I also followed another approach something like (from developer.apple.com)
`
(IBAction)syncOnThreadAction:(id)sender
{
[self willStartJob];
[self performSelectorInBackground:
#selector(inThreadStartDoJob:)
withObject:theJobToDo
];
}
(void)inThreadStartDoJob:(id)theJobToDo
{
NSAutoreleasePool * pool;
NSString * status;
pool = [[NSAutoreleasePool alloc] init];
assert(pool != nil);
status = [... do long running job specified by theJobToDo ...]
[self performSelectorOnMainThread:
#selector(didStopJobWithStatus:)
withObject:status
waitUntilDone:NO
];
[pool drain];
}
`
The problem with this was that, it is showing the acitivityVIewIndicator spinning correctly (at least on the simulator) but after it stops, the built in activity indicator in the top bar (where it shows the battery% etc) is still spinning.
I'm new to objective C. I have finished my app completely but for this silly thing. I realize there is no way to display UIActivityView without starting another thread. and finally, just to rant, I don't understand why they have to make it so complicated. I mean they knew it was going to have this problem, why not provide a sample code everyone can use rather than deriving their own solutions.
Finally, can anyone please provide me with a direction or some sample code. I would really appreciate it. I have been searching for a few hours now and have not found anything really that works!
Why are you starting/stopping the indicator on a separate thread? Any methods you send to your UIActivityIndicatorView must be sent on the main (UI) thread.
Any events sent by a button pressed will automatically be run on the main thread. If you're using background threads to complete the process, you could do something like:
- (IBAction)buttonPressed:(id)sender {
// This runs on the main thread
[activityIndicator startAnimating];
[self performSelectorInBackground:#selector(inThreadStartDoJob:) withObject:theJobToDo];
}
- (void)inThreadStartDoJob:(id)theJobToDo {
// Set up autorelease pool
...
// Run your long-running action
...
// Stop the spinner. Since we're in a background thread,
// we need to push this to the UI Thread
[activityIndicator performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:YES];
}
Edit: As for the activity indicator in the top bar (where the battery is), doesn't this automatically start/stop based on network activity?

Refresh iPhone For progressbar

How would i show that the progress bar is working there is no Refresh() in objective-c like there is in .net what would i use
for example
contactprogress.progress = 0.5;
StatusLabel.text = #"Status: Address Found";
How would i refresh the view to show that the progress has changed & show user the StatusLabel status?
Thanks
Mason
Based on your comments to the other two responses, you're doing some computationally intensive task that takes a few seconds, and the view is not updating during the task. You could try using two threads (not as scary as it sounds) so that the UI can continue updating while the task is doing its thing.
Here is an example.
iOS Reference Library Threading Programming Guide
It sounds like you want to update a progress bar and some text repeatedly with some time interval between. You could use a simple timer. Read about timers here. Perhaps something like this:
[NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:#selector(refreshProgress) userInfo:nil repeats:YES];
and:
- (void) refreshProgress:(id)sender {
// figure out new progress bar and text values
contactprogress.progress = 0.5;
StatusLabel.text = #"Status: Address Found";
// check if we should stop the timer and hide the progress bar/status text
}
That would update your progress bar with new values every 0.1 seconds.
To redraw an UIView, you can use
[UIView setNeedsDisplay];
However, you will need this only in very rare cases. When you change, let's say the contents of a label, your UI should update instantly. You might want to provide more code/context for your problem.

Display a loading icon while a network resource is being downloaded

I'm trying to display a loading icon while my iPhone app downloads a network resource, but I can't figure out how to make it show up correctly.
I searched around and found some details on the UIActivityView class, but the available example source code didn't work, and the documentation is kind of terse.
Could someone provide a simple example on how to use this class?
Assuming you've got a view controller set up, and would like to add a UIActivityIndicator to it, here's how you could do it:
(assume you've got a member variable called indicator, which you can use later to clean up)
For your interface (.h file):
UIActivityIndicator *indicator;
For your implementation (.m file):
Start the Animation
CGRect b = self.view.bounds;
indicator = [[UIActivityIndicator alloc] initWithActivityIndicatorStyle:
UIActivityIndicatorStyleWhite];
//center the indicator in the view
indicator.frame = CGRectMake((b.size.width - 20) / 2, (b.size.height - 20) / 2, 20, 20);
[self.view addSubview: indicator];
[indicator release];
[indicator startAnimating];
Stop the Animation
[indicator removeFromSuperview];
indicator = nil;
Ben answer looks pretty similar to what I'm doing - your guess about the thread is probably accurate. Are you using NSURLConnection to handle your downloading? If so, are you using the synchronous or asynchronous version? If it's the synchronous version and you're simply starting and stopping the animation around the synchronous call, then the UI isn't updating until after the you've stopped the animation.