照著網(wǎng)上的教程,吭哧吭哧寫(xiě)好了一個(gè)tableView,Run起來(lái),界面出現(xiàn)了。還來(lái)不及高興一下,一滾動(dòng),坑爹啊,直接crash掉了,退出。
打開(kāi)調(diào)試模式,再重現(xiàn)一次,Debugger Console顯示的結(jié)果是“Program received signal: "EXC_BAD_ACCESS"”.
這個(gè)結(jié)果表示代碼中有數(shù)組越界或者哪里內(nèi)存泄漏了。(網(wǎng)上教程不靠譜啊,完全照著教程敲代碼竟然都錯(cuò)了)
還好總共沒(méi)幾個(gè)方法,多加幾個(gè)斷點(diǎn)調(diào)試一下。
問(wèn)題出來(lái)了:
當(dāng)向下滾動(dòng),調(diào)用cellForRowAtIndexPath消息時(shí),執(zhí)行到第25行代碼tableData已經(jīng)被回收了。
問(wèn)題分析:
數(shù)組初始化放在viewDidLoad消息中,照著教程敲使用
arrayWithObjects來(lái)創(chuàng)建。從語(yǔ)法上講,此方法是autorelease的,不需要我們手動(dòng)去release。
然而問(wèn)題也出在這,當(dāng)向下滾動(dòng)時(shí),不知為何在viewDidLoad初始化的數(shù)組都已經(jīng)被回收了。
修正方案:
把viewDidLoad消息中數(shù)組創(chuàng)建方法都改為[
[NSArray alloc] initWithObject: ……];方式創(chuàng)建,再在dealloc中釋放掉就OK了。
推斷總結(jié):
此代碼的界面是用IB拉出來(lái)的,對(duì)于新人來(lái)說(shuō)我們并不清楚它的view的創(chuàng)建細(xì)節(jié)。從執(zhí)行效果來(lái)看,它在創(chuàng)建view時(shí)嵌套了個(gè)NSAutoreleasePool,向下滾動(dòng)時(shí)已經(jīng)把pool給release掉了,所以出現(xiàn)crash。
得到教訓(xùn)就是:使用IB創(chuàng)建界面時(shí),那些自定義的對(duì)象盡量使用alloc/retain/copy方式創(chuàng)建,自己release。把內(nèi)存管理寄托在自動(dòng)釋放池中是不靠譜的,除非這個(gè)池是你自己創(chuàng)建并釋放的。
源代碼如下
1
2 - (void)viewDidLoad {
3 [super viewDidLoad];
4 tableData = [NSArray arrayWithObjects:@"香辣醬香骨",@"肉末燒豆腐",@"芙蓉蝦",@"紅燒帶魚(yú)",
5 @"粉蒸排骨",@"自來(lái)紅月餅",@"蛋黃蓮蓉月餅",@"南瓜奶酪蛋糕",
6 @"南瓜沙拉",@"五香毛豆",@"奶油冰淇淋",@"焦糖南瓜冰淇淋",nil];
7 thumbnails =[NSArray arrayWithObjects:@"a.jpg",@"b.jpg",@"c.jpg",@"d.jpg",@"e.jpg",@"f.jpg",
8 @"g.jpg",@"h.jpg",@"i.jpg",@"j.jpg",@"k.jpg",@"l.jpg",nil];
9 prepTime = [NSArray arrayWithObjects:@"10 min",@"5 min",@"5 min",@"10 min",@"8 min",@"30 min",
10 @"30 min",@"45 min",@"20 min",@"5 min",@"50 min",@"40 min",nil];
11 }
12
13 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
14 return [tableData count];
15 }
16
17 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
18 static NSString *simpleTableIdentifier = @"SimpleTableItem";
19 SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
20 if(cell == nil){
21 NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"SimpleTableCell" owner:self options:nil];
22 cell = [nib objectAtIndex:0];
23 }
24 NSUInteger row = [indexPath row];
25 cell.nameLabel.text = [tableData objectAtIndex:row];
26 cell.thumbnailImageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:row]];
27 cell.prepTimeLabel.text = [prepTime objectAtIndex:row];
28 return cell;
29 }
30
31 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
32 return 78;
33 }
34
35 - (void)dealloc {
36 [super dealloc];
37 }