简体   繁体   English

滚动时UITableView崩溃

[英]UITableView crashes when scrolling

I've been attempting to create my own app for a band by my friends, and I've been experimenting with using a custom TableViewCell for news articles that appear on the website. 我一直在尝试为我的朋友创建一个乐队的应用程序,我一直在尝试使用自定义的TableViewCell来显示网站上的新闻文章。 My main objective is to get all of the data from the website, store it in a NSMutableArray, and then display that in my custom cells. 我的主要目标是从网站获取所有数据,将其存储在NSMutableArray中,然后在我的自定义单元格中显示。

The app runs fine when it loads the first 5-6 cells. 应用程序在加载前5-6个单元格时运行正常。 However, when I begin to scroll, the app crashes. 但是,当我开始滚动时,应用程序崩溃了。 I've pinpointed the in the cellForRowAtIndexPath: method. 我已经在cellForRowAtIndexPath:方法中找到了它。 Using GDB, I've also come to find out that after I create my NSMutableArray data and once the program runs, after scrolling, my array seems to be autoreleased. 使用GDB,我也发现在创建NSMutableArray数据后,一旦程序运行,滚动后,我的数组似乎是自动释放的。 I'm not sure why this happens. 我不确定为什么会这样。 Here's what I have for my code thus far: 这是我到目前为止我的代码所拥有的:

In HomeViewController.h: 在HomeViewController.h中:

@interface HomeViewController : UIViewController {
    NSArray *results;
    NSMutableArray *titles;
    NSMutableArray *dates;
    NSMutableArray *entries;
}

@property (nonatomic, retain) NSMutableArray *titles;
@property (nonatomic, retain) NSMutableArray *dates;
@property (nonatomic, retain) NSMutableArray *entries;

@end

In HomeViewController.m: 在HomeViewController.m中:

- (void)viewDidLoad {
[super viewDidLoad];
titles = [[NSMutableArray alloc] init];
dates = [[NSMutableArray alloc] init];
entries = [[NSMutableArray alloc] init];

while((i+1) != endIndex){   
    NSString *curr_title = [[NSString alloc] init]; 
    NSString *curr_date = [[NSString alloc] init];
    NSString *curr_entry = [[NSString alloc] init];

    //do some character iterations across a string

    [titles addObject:curr_title];
    [dates addObject:curr_date];
    [entries addObject:curr_entry];

    [curr_title release];
    [curr_date release];
    [curr_entry release];
}
}

//more code here, removed //这里有更多代码,已删除

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"NewsCell";


NewsCell *cell = (NewsCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {
    NSArray *topLevelObjects = [[NSBundle mainBundle]
                                loadNibNamed:@"NewsCell"
                                owner:self options:nil];
//  cell = [topLevelObjects objectAtIndex:0];
    for(id currentObject in topLevelObjects){
        if([currentObject isKindOfClass:[UITableViewCell class]]){
            cell = (NewsCell *)currentObject;
            break;
        }
    }

}
NSLog(@"%d", indexPath.row);
NSLog(@"%d", titles.count);
cell.cellTitle.text = [titles objectAtIndex:indexPath.row];
cell.datePosted.text = [dates objectAtIndex:indexPath.row];
cell.preview.text = [entries objectAtIndex:indexPath.row];

return cell;
}

Again, the first 5-6 cells show up. 再次,前5-6个细胞出现。 Once I scroll, I tried doing po titles and got this error: 一旦我滚动,我尝试做po titles并得到这个错误:

Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_PROTECTION_FAILURE at address: 0x00000009 0x011b309b in objc_msgSend ()

I've tried allocating the arrays in initWithNibName: but that didn't seem to do much. 我已经尝试在initWithNibName:分配数组initWithNibName:但这似乎没有做太多。 I've tried moving all the code in viewDidLoad: and then calling [super viewDidLoad] and it just produced the same results as well. 我试过在viewDidLoad:移动所有代码viewDidLoad:然后调用[super viewDidLoad] ,它也产生了相同的结果。 Sorry this is so long, but I figured people needed to see my code. 对不起,这太长了,但我想人们需要看到我的代码。

I don't see anything obviously wrong with the code you posted. 我发布的代码没有看到任何明显错误。 Try enabling the NSZombieEnabled environment variable . 尝试启用NSZombieEnabled环境变量 This prevents objects from being released so that when your application "crashes" you can determine which object caused the problem. 这可以防止对象被释放,这样当您的应用程序“崩溃”时,您可以确定哪个对象导致了问题。

Also, instead of looping through array of objects returned by loadNibNamed:owner:options , you should assign the desired object to an IBOutlet property of your class. 此外,您应该将所需对象分配给类的IBOutlet属性,而不是循环遍历loadNibNamed:owner:options返回的对象数组。 See Loading Custom Table-View Cells From Nib Files for an example. 有关示例,请参阅从Nib文件加载自定义表格查看单元格


The following is extracted from the new code you posted: 以下是从您发布的新代码中提取的:

NSString *curr_title = [[NSString alloc] init];

//do some character iterations across a string

[titles addObject:curr_title];

[curr_title release];

NSString is not mutable (as is NSMutableString). NSString不可变(与NSMutableString一样)。 Are you intentionally adding empty strings to the titles array? 你是否故意在titles数组中添加空字符串?


In response to your comment: stringByAppendingString creates a new autoreleased NSString object. 响应您的注释: stringByAppendingString创建一个新的自动释放的NSString对象。

NSString *curr_title = [[NSString alloc] init];

// this leaks the original NSString object (curr_title no longer points to it);
// curr_title now points to a new, autoreleased NSString
curr_title = [curr_title stringByAppendingString:@"..."];

[titles addObject:curr_title];

// releasing the autoreleased NSString will cause your application to crash!
[curr_title release];

The problem might be with the implementation of NewsCell, all your properties there being retained? 问题可能出在NewsCell的实施上,所有属性都被保留了?

Also, any reason HomeViewController is subclassing UIViewController and not UITableViewController? 另外,HomeViewController是UIViewController的子类而不是UITableViewController的任何原因?

And this should work just fine: 这应该工作得很好:

NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"NewsCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];

*EXC_BAD_ACCESS* is a sure sign that one of your objects is getting over released (or wasn't retained properly). * EXC_BAD_ACCESS *是一个确定的迹象,表明您的某个对象已经过度释放(或未正确保留)。 NSZombieEnabled is your friend here, just as titaniumdecoy suggests - figuring out what object is being over released is half the battle. NSZombieEnabled在这里是你的朋友,正如titaniumdecoy建议的那样 - 弄清楚什么对象被释放是一半的战斗。 Just be sure to turn it off before releasing the app, because (as titaniumdecoy pointed out) it prevents objects from getting released. 请务必在发布应用程序之前关闭它,因为(正如钛指出的那样)它可以防止对象被释放。

I usually use a combination of NSZombieEnabled and well placed breakpoints (so I can walk through the code till it crashes) to figure out where the problem is cropping up in the code. 我通常使用NSZombieEnabled和放置良好的断点的组合(所以我可以遍历代码直到它崩溃)来找出问题在代码中出现的位置。 Then it's usually a simple matter of backtracking to figure out where the object was over released. 然后通常只需回溯即可找出物体释放的位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM