I've managed the modestly simple task of getting a progress bar to work on my iPhone. I include two examples to show what didn't work and what did. They are an update to the Apple TrivialThreads examples from 1997.
It was a bit trickier than I expected. I had thought that I could simply spawn a thread, do the work in the background thread, and update the progress bar as the background thread did it's thing. To no avail. The Apple Cocoa framework isn't reentrant, so Cocoa doesn't let the main thread do anything until the background thread is done. Seems to me it's really busted - isn't that the majority of what you'd want threading to do? Do something and allow the GUI to keep going? The following fragment illustrates what I thought would work, but doesn't:
- (void)doSomethingSlow:(id)sender
{
[self outputString:@"doSomethingSlower:\n"];
[NSThread detachNewThreadSelector:@selector(slowTransfer) toTarget:self withObject:nil];
}
- (void) doneTransfer
{
NSLog(@"DoneTransfer");
}
- (void)slowTransfer
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// do processing here.
[self setProgressValue:....];
// When done...
[self performSelectorOnMainThread:@selector(doneTransfer) withObject:nil waitUntilDone:YES];
[pool release];
}
The full example is TrivialThreadsScreenDoesntRefresh.zip
It takes a completely separate Server to do the work, and then inter-process communication to relay the progress information. This is available at TrivialThreads3.zip.
One application note: I used a string for the progress value instead of a float because I couldn't get floats to transfer properly. My guess is that the float is being passed by reference rather than by value, and the client can't get back to the float.
It was a bit trickier than I expected. I had thought that I could simply spawn a thread, do the work in the background thread, and update the progress bar as the background thread did it's thing. To no avail. The Apple Cocoa framework isn't reentrant, so Cocoa doesn't let the main thread do anything until the background thread is done. Seems to me it's really busted - isn't that the majority of what you'd want threading to do? Do something and allow the GUI to keep going? The following fragment illustrates what I thought would work, but doesn't:
- (void)doSomethingSlow:(id)sender
{
[self outputString:@"doSomethingSlower:\n"];
[NSThread detachNewThreadSelector:@selector(slowTransfer) toTarget:self withObject:nil];
}
- (void) doneTransfer
{
NSLog(@"DoneTransfer");
}
- (void)slowTransfer
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// do processing here.
[self setProgressValue:....];
// When done...
[self performSelectorOnMainThread:@selector(doneTransfer) withObject:nil waitUntilDone:YES];
[pool release];
}
The full example is TrivialThreadsScreenDoesntRefresh.zip
It takes a completely separate Server to do the work, and then inter-process communication to relay the progress information. This is available at TrivialThreads3.zip.
One application note: I used a string for the progress value instead of a float because I couldn't get floats to transfer properly. My guess is that the float is being passed by reference rather than by value, and the client can't get back to the float.
Leave a comment