gikoha’s blog

個人的メモがわり

UIActivityIndicatorViewを回す

そもそもUIActivityIndicatorViewを使いたいのは、処理のかかる作業をさせたいわけだ
id:uedam0322:20090206 にUIActivityIndicatorViewについて記載がある

UIActivityIndicatorViewをくるくる回すには別スレッドを立ち上げ、そちらで重い処理を行い、
メインスレッドではくるくるを表示させる。

ところが別スレッドで重い処理をさせる場合でも

  1. 裏でthread safeでないUIKitが動いているから、その別スレッドではthread safeなことしかできない=Core Data系はかなり全滅
  2. せいぜい使えるのはFoundation, それもファイル入出力系はいまのところダメ, 使うのならlock/@synchronizedしてね
  3. UIKitをそのThreadで使いたければperformSelectorOnMainThread を使ってmain threadで処理させる
  4. もちろん別スレッドになっているのでAutorelease Poolを別にたてないとメモリリークしまくり

結局こんなコードにしましたが大丈夫かな?

-(void)someJobFinish
{
	[activityView stopAnimating];		// 一応UIKitのAPIなのでThread外で..

	UIAlertView *alert = [[UIAlertView alloc]
						  initWithTitle:@"Finished"
						  message:someString
						  delegate:nil
						  cancelButtonTitle:@"OK"
						  otherButtonTitles:nil];
	[alert show];
	[alert release];
	[someString release];
}

-(void)someJob
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
	int i;
	NSString *str;

	// このスレッド内ではThreading SafeなAPIしか使わないように
	for(i=0;i<100;i++)
	{	// 重い処理のつもり
		str = [NSString stringWithFormat:@"%i",i];
	}
	[NSThread sleepForTimeInterval:1.0];
	
	
	@synchronized(self)
	{
		someString = [str retain];	// 戻す値をインスタンス変数に格納する
	}
	[self performSelectorOnMainThread:@selector(someJobFinish) withObject:nil waitUntilDone:NO];
	[pool release];	// ゴミ掃除
	[NSThread exit];
}

-(IBAction)pressStart:(id)sender
{	// activityViewを回すボタンにリンクしてあります
	someString = nil;
	[activityView startAnimating];
	[NSThread detachNewThreadSelector:@selector(someJob) toTarget:self withObject:nil];
}