読者です 読者をやめる 読者になる 読者になる

Life is Really Short, Have Your Life!!

ござ先輩の主に技術的なメモ

cellForRowAtIndexPathでのスクロール処理でクラッシュ・・・

iPhone iPad

Flexでもそうなんだけど、スクロールが走るということは画面の再描画を行って行数に合わせてセルのデータをセットするという処理を行うことになる。

で、これが単純なラベルだったらいいんだけど、今回はめっちゃ複雑な作りになってしまってる。NSArrayの下に2つNSDicitonaryが入っている。それが1つのオブジェクトとなって1行のデータを構成している。


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
	static NSString *identifier = @"MainMenuCell";
	MainMenuCell *mainCell= (MainMenuCell *)[tableView dequeueReusableCellWithIdentifier:identifier];	

	if (mainCell == nil) {		
 	   //セル毎にデータ領域をalloc
		NSArray *arr = [[NSArray alloc]init];				
		NSDictionary *left = [[NSDictionary alloc]init];
		NSDictionary *right = [[NSDictionary alloc]init];
		//このコードを書くと落ちる。
                //コメントアウトすると落ちない。
                arr = [cellData objectAtIndex:0];
		[left release];
		[right release];
		[arr release];
	}
return mainCell;
}
- (void)viewDidLoad {
//cellDataはこのUIViewControllerのプロパティ
cellData = [[[NSMutableArray alloc]initWithCapacity:2]autorelease];

	NSDictionary *left = [NSDictionary dictionaryWithObjectsAndKeys:
	   @"F86966",@"a",
	   @"100",@"b",
	   @"300",@"c",
	   nil
	   ];
	
	NSDictionary *right 
	= [NSDictionary dictionaryWithObjectsAndKeys:
	   @"F86967",@"a",
	   @"50",@"b",
	   @"1000",@"c",
	   nil
	   ];
	NSArray *arr = [[NSArray alloc]initWithObjects:left,right,nil];
	[cellData addObject:arr];
	[arr release];
}

で、このViewContollerのviewDidLoadでNSMutableArrayのオブジェクトをalloc init autorelaseして、適当なテストデータを作ってオブジェクトを追加している。テストデータはそこでreleaseしてる。

クラスのプロパティになっているオブジェクトのデータをセルの初期化のタイミングで突っ込んであげたいんだけど、落ちてしまう。リリースがまずいのかなぁ・・・。

ちょうど今日で延べ2週間ぐらいか。まだまだ先は長いや。

追記 2010.09.01

Masato Ikeda (ikm)さんはTwitterを使っていますさんのこのご指摘がズバリでした。問題解決。

@gothedistance あと抜粋されて抜けてるだけかもしれませんが、NSArray *arr = ~で宣言したarrは[cellData objectAtIndex:0];を代入する前にreleaseしておかないとメモリリークしてしまう気がします。

http://twitter.com/ikm/status/22620365318

これがリークにつながる理由がまだわかっていないのですが、cellForRowAtIndexPathをこう書き換えると落ちずに、自分の望むデータが初期化されました。

if (mainCell == nil) {	 	
                //alloc initした後に
                NSArray *arr = [[NSArray alloc]init];				
		NSDictionary *left = [[NSDictionary alloc]init];
		NSDictionary *right = [[NSDictionary alloc]init];		
		//リリースして
                [left release];
		[right release];
		[arr release];
		//オブジェクトを代入
                arr = [cellData objectAtIndex:0];
		left = [arr objectAtIndex:0];
		right = [arr objectAtIndex:1];	
}

僕の感覚だとallocしてreleaseしたものを代入したら、それこそメモリリークしそうに感じる。Hoge hoge = new Hoge();hoge = null;ってやっているように感じるから。が、実際問題、alloc initしてreleaseしたものを代入したら問題なくスクロールされた。とっても不思議の国のアリス。なんでなんだろう。