Link to home
Start Free TrialLog in
Avatar of ehensens
ehensensFlag for United States of America

asked on

iPhone app development: UIProgressView won't update within a for loop

Hi everyone,

I have a UIProgressView that I want to update within a for loop, see the code. However, the progress view won't update itself while in the for loop, it just jumps from 0 to 1! Is this a matter of the progress view not being fast enough? What is the deal here, and how can I make this progress view work?

Thanks in advance for your help!
DownloadProgressView.progress = 0;
 
for (iDownloadIteration = 0; iDownloadIteration < iIterations; iDownloadIteration++)
{
	DownloadProgressView.progress = (float)iDownloadIteration / (float)iIterations;
        //other stuff here..
}
 
DownloadProgressView.progress = 1.0;

Open in new window

Avatar of AGoodKeenMan
AGoodKeenMan
Flag of New Zealand image

I'm not 100% certain on this, but I think the UI can only be updated on the main thread, so if the main thread is busy doing aLongTask: then the UI is not updated until the aLongTask: returns, so you may need to perform the download in a background thread with performSelectorInBackground:@selector() and then update your UIProgressView with performSelectorOnMainThread:@selector(). Also you could use the UINotificationCentre
Avatar of ehensens

ASKER

Hi AGoodKeenMan,

Thank you for your comment. Do you think you might elaborate just a bit on exactly how to use performSelectorInBackground:@selector() and performSelectorOnMainThread:@selector() ? I'm not quite sure how to use those. Thanks for your help!
ASKER CERTIFIED SOLUTION
Avatar of AGoodKeenMan
AGoodKeenMan
Flag of New Zealand image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ooh, thank you for the code. I just popped into work (I don't check this account at home) so give me a little while to try out what you have (I'm not ignoring your comments).
Hey,

Thanks again for the code. I tried it out and I'm not getting any changes in the result. I had a couple questions:

1) How come you're never using the variable "pool"? Does that variable have any purpose?
2) How come you're setting waitUntilDone to NO, isn't the whole point to make it wait until the update is done and only then continue? However, I tried it with it set to YES and it didn't make any difference at all.
3) Did that code work for you?

I'm very frustrated. This seems to be too hard for what it is - if this is as hard as it appears to be then Apple made a huge mistake with this UIProgressView class. People should be able to update a progress bar without having to - sleep the main thread - or any other voodoo.

Here's the basic code as I have it. Any other ideas?





float fProgressValue;
 
 
 
-(IBAction)PushDownloadImageButton:(id)sender
{
	fProgressValue = 0.0;
	[self performSelectorOnMainThread:@selector(SetProgressBar) withObject:nil waitUntilDone:YES];
	
	[self performSelectorOnMainThread:@selector(DownloadNow) withObject:nil waitUntilDone:YES];
}
 
 
 
-(void)DownloadNow
{
	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
 
	// Other code here...
 
		for (iDownloadIteration = 0; iDownloadIteration < iIterations; iDownloadIteration++)
		{
			//[NSThread sleepForTimeInterval:0.1]; //pause the background thread
			fProgressValue = (((float)iDownloadIteration)/((float)iIterations));
			//[self SetProgressBar];
			[self performSelectorOnMainThread:@selector(SetProgressBar) withObject:nil waitUntilDone:NO];
 
			// Other stuff here...
		}
 
	fProgressValue = 0.5;
	[self performSelectorOnMainThread:@selector(SetProgressBar) withObject:nil waitUntilDone:NO];
	
	[pool release];
}
 
 
 
-(void)SetProgressBar
{
	[DownloadProgressView setProgress:fProgressValue];
}

Open in new window

Sorry I didn't mean to overwhelm you. Please don't get put off, its probably my fault for not explaining things well enough.

1. Every new thread we start should have an autorelease pool and since your downloadNow method is run in  a background thread it needs its own autorelease pool. You can read more about it here:
http://developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/uid/20000047

2. If waitUntilDone is set to YES, the background thread will wait until setProgressBar returns before it resumes execution. Which would halt the download for a short period of time and we don't want that. You can read more about NSObject here:
http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/performSelectorOnMainThread:withObject:waitUntilDone:

3. Yes, I just tested it in a new project.

The reason I sleep the background thread is just to simulate your download process and give you some visual feedback, it is not necessary for your solution, however if you don't have some sort of delay in this example the progress bar will appear to go from 0 to 1 instantly, because without anything for the for loop to do, it will execute very fast.

In your code above what is the value of iIterations?

I am not at work at the moment, but in the morning I will post a link so you can download myTest example.
EE won't allow me to attach the example project, so you can download it from my iDisk here:
files.me.com/robcarruthers/dbhrbq
(this link will expire in 30 days)
Well, I accept that your solution works - turns out my problem must be something else. One of the things I'm doing many times while downloading is calling an outside C++ class, and the program keeps crashing on that line (accessing bad memory). But, before it does, I can see the progress view update itself. I don't know why it's crashing, it must have something to do with the different threads because the class works like a charm normally. Oh well, thanks for all your help.