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

ehensensAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

AGoodKeenManCommented:
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
0
ehensensAuthor Commented:
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!
0
AGoodKeenManCommented:
Ok, this is a bit rough, but assuming an IBAction starts theLongTask, the following code should work as a test.
Also I meant NSNotificationCenter in the above comment, It would be a nice solution aswell. You can read more here:
http://developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/Notifications/Introduction/introNotifications.html
http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html
//----------------------------------------------------------------
- (IBAction)startTheLongTask
{
	[progressBar setProgress:0.0];
	[self performSelectorInBackground:@selector(aLongTask) withObject:nil];
}
//----------------------------------------------------------------
- (void)aLongTask
{
        // download code goes here...
 
	// you need an autoRelease pool for the background thread
	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
 
        // simulate a long download task
	NSInteger i;
	for ( i = 0 ; i < 100 ; i++ )
	{
		[NSThread sleepForTimeInterval:0.1]; //pause the background thread
		//Update the progressBar
		[self performSelectorOnMainThread:@selector(updateProgressBar) withObject:nil waitUntilDone:NO];
	}
	
	[pool release];
}
//----------------------------------------------------------------
- (void)updateProgressBar
{
	float p = [progressBar progress];
	[progressBar setProgress:p + 0.01];
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

ehensensAuthor Commented:
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).
0
ehensensAuthor Commented:
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

0
AGoodKeenManCommented:
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.
0
AGoodKeenManCommented:
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)
0
ehensensAuthor Commented:
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.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Swift Programming

From novice to tech pro — start learning today.