iPhoneレシピ4:UIActionSheetにプログレスバーを表示する

ポイント

UIActionSheetの高さはタイトルの改行か、setNumberOfRowsメソッドで設定する。ただしsetNumberOfRowsはドキュメントには載っていないメソッド。
UIActionSheetはメインスレッドで表示しないと、ボタンが効かないっぽい。また、表示とその他の処理を同一スレッド内で行うと、処理終了までUIActionSheetが表示されない。

ソース

Download source

UIActionSheetの組み立て部分はこんな感じ。

- (void)viewDidLoad {
    [super viewDidLoad];
	actionSheet = [[UIActionSheet alloc] initWithTitle:@"Please wait\n\n\n\n" 
											  delegate:self 
									 cancelButtonTitle:NSLocalizedString(@"Cancel",nil) 
								destructiveButtonTitle:nil 
									 otherButtonTitles:nil];
	progressBar = [[UIProgressView alloc] initWithFrame:CGRectMake(30.0f, 40.0f, 240.0f, 90.0f)];
	progressBar.progressViewStyle = UIProgressViewStyleDefault;
	progressBar.progress = 0.0f;
	[actionSheet addSubview:progressBar];
	
	progressLabel = [[UILabel alloc] initWithFrame:CGRectMake(30.0f, 50.0f, 240.0f, 20.0f)];
	progressLabel.backgroundColor = [UIColor clearColor];
	progressLabel.textColor = [UIColor whiteColor];
	progressLabel.font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
	[actionSheet addSubview:progressLabel];
}

表示と処理のスレッド分けはこんな感じ。

- (IBAction)start {
	cancelFlag = NO;
	// UIActionSheetはメインスレッドで表示しないとボタンが効かないっぽい。
	[self showSheet];
	[self performSelectorInBackground:@selector(doProcess) withObject:nil];
}

- (void)showSheet {
	progressBar.progress = 0;
	progressLabel.text = NSLocalizedString(@"Processing...", nil);
	[actionSheet showInView:self.view];
}

// 何かしらの処理
- (void)doProcess {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	@try {
		for (int i=0; i<100; i++) {
			if (cancelFlag) return;

			// Background threadで動いている時はUIProgressViewをMainThreadで動かすこともできる。
			// どちらで動かすべきかはよく分からない。
//			[self performSelectorOnMainThread:@selector(progress:) withObject:[NSNumber numberWithFloat:0.01f] waitUntilDone:NO];
			[self performSelectorInBackground:@selector(progress:) withObject:[NSNumber numberWithFloat:0.01f]];
			[NSThread sleepForTimeInterval:0.1f];
		}
		[actionSheet dismissWithClickedButtonIndex:-1 animated:YES];
	}
	@finally {
		[pool release];
	}
}

- (void)progress:(NSNumber *)amount {
	progressBar.progress += [amount floatValue];
	NSLog(@"%f", progressBar.progress);
}

///////////////////////////////////////////////////////////////////
// UIActionSheetDelegate implements
//
- (void)actionSheet:(UIActionSheet *)sheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
	if (buttonIndex == sheet.cancelButtonIndex) {
		cancelFlag = YES;
	}
}