I have been trying to play around with this for a long time and I can't seem to find the best approach. I am getting confused because there seem to be different answers/opinions on how to accomplish this seemingly simple task.
I want to be able to have a reusable class called ActivityIndicatorController. This controller has two main methods: activateIndicator and deactivateIndicator. It takes a UIView as an argument/property as well as an NSString for a label. Upon activation, it will turn off user interaction in the UIView and add a rectangle subview (with alpha and rounded corners), a UIActivityIndicator control and a UILabel for the status text. This is desirable because that way I don't have to have custom UIActivityIndicatorView code in each view controller or to have to set up an ActivityIndicator in each NIB.
The problem I am fundamentally having is how to kick off this process of adding and animating the ActivityIndicator. Some methods I have tried don't display the new view at all. Others work, but the ActivityIndicator doesn't animate.
I have tried using [NSThread detachNewThreadSelector:@selector(startAnimating) toTarget:activityIndicator withObject:nil] inside the activateIndicator method, but that doesn't display the new UIView.
I have tried using [NSThread detachNewThreadSelector:@selector(activateIndicator) toTarget:activityIndicatorController withObject:nil] from a calling method, but this would put the whole creation of the new UIView in a separate thread.
Now to the question:
Part 1: I understand that all UI should be handled on the main thread, is that correct?
Part 2: What is the difference/advantage/disadvantage of using [NSThread detachThreadSelector] versus NSOperation?
Part 3: Is it better to:
(a) send the lengthy operation to a new background thread with a callback to the main thread OR
(b) send the UIActivityIndicatorView startAnimating method to a separate thread and run the lengthy process on the main thread
AND why?
Here is my current code:
ActivityViewController class:
-(void)activateIndicator {
NSLog(@"activateIndicator called");
if (isActivated || !delegateView)
return;
NSLog(@"activateIndicator started");
[delegateView.view setUserInteractionEnabled:NO];
[delegateView.navigationController.view setUserInteractionEnabled:NO];
[delegateView.tabBarController.view setUserInteractionEnabled:NO];
float w = [[UIScreen mainScreen] bounds].size.width;
float h = [[UIScreen mainScreen] bounds].size.height;
NSLog(@"Width = %f\nHeight = %f", w, h);
if (!disabledView) {
disabledView = [[[UIView alloc] initWithFrame:CGRectMake((w - kNormalWidth) / 2.0, (h - kNormalHeight) / 2.0, kNormalWidth, kNormalHeight)] autorelease];
disabledView.center = [[[delegateView.view superview] superview] center];
[disabledView setBackgroundColor:[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.85]];
CALayer *layer = [disabledView layer];
NSLog(@"layer=%@",layer);
NSLog(@"delegate=%@",[layer delegate]);
layer.cornerRadius = 12.0f;
}
if (!activityIndicator) {
activityIndicator = [[[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(kNormalWidth / 2, 10.0f, 40.0f, 40.0f)] autorelease];
[activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator.center = disabledView.center;
}
if (!activityLabel) {
activityLabel = [[[UILabel alloc] initWithFrame:CGRectMake(10.0f, 100.0f, kNormalWidth - 20, 38)] autorelease];
activityLabel.text = labelText;
activityLabel.textAlignment = UITextAlignmentCenter;
activityLabel.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.0f];
activityLabel.textColor = [UIColor colorWithWhite:1.0f alpha:1.0f];
activityLabel.center = disabledView.center;
}
[[[delegateView.view superview] superview] addSubview:disabledView];
[[[delegateView.view superview] superview] addSubview:activityIndicator];
[[[delegateView.view superview] superview] addSubview:activityLabel];
[NSThread detachNewThreadSelector:@selector(startAnimating) toTarget:activityIndicator withObject:nil];
}
Calling Code from multiple places in the app:
ActivityIndicatorController *aic = [[ActivityIndicatorController alloc] init];
aic.delegateView = self;
aic.labelText = @"Test...";
[aic activateIndicator];
//DO LENGTHY WORK ON MAIN THREAD
[aic deactivateIndicator];
[aic release], aic = nil;