我有这个简单的 UITableView,每个单元格都有一个与之对应的图像。我所做的只是在每个单元格中显示图像的标题和图像本身。这是我的 cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// this is where the data for each cell is
NSDictionary *dataForThisCell = cachedData.posts[indexPath.row][@"data"];
// this creates a new cell or grabs a recycled one, I put NSLogs in the if statement to make sure they are being recycled, they are.
post *cell = (post *) [self.tableView dequeueReusableCellWithIdentifier:@"postWithImage"];
if (cell == nil) {
cell = [[[NSBundle mainBundle]loadNibNamed:@"postWithImage" owner:self options:nil]objectAtIndex:0];
[cell styleCell];
}
// if this cell has an image we need to stick it in the cell
NSString *lowerCaseURL = [dataForThisCell[@"url"] lowercaseString];
if([lowerCaseURL hasSuffix: @"gif"] || [lowerCaseURL hasSuffix: @"bmp"] || [lowerCaseURL hasSuffix: @"jpg"] || [lowerCaseURL hasSuffix: @"png"] || [lowerCaseURL hasSuffix: @"jpeg"]) {
// if this cell doesnt have an UIImageView, add one to it. Cells are recycled so this only runs several times
if(cell.preview == nil) {
cell.preview = [[UIImageView alloc] init];
[cell.contentView addSubview: cell.preview];
}
// self.images is an NSMutableDictionary that stores the width and height of images corresponding to cells.
// if we dont know the width and height for this cell's image yet then we need to know now to store it
// once the image downloads, and then cause our table to reload so that heightForRowAtIndexPath
// resizes this cell correctly
Boolean shouldReloadData = self.images[dataForThisCell[@"name"]] == nil ? YES : NO;
// download image
[cell.preview cancelImageRequestOperation];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString: dataForThisCell[@"url"]]];
[request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
[cell.preview setImageWithURLRequest: request
placeholderImage: [UIImage imageNamed:@"thumbnailLoading.png"]
success: ^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
// if we indicated earlier that we didnt know the dimensions of this image until
// just now after its been downloaded, then store the image dimensions in self.images
// and tell the table to reload so that heightForRowAtIndexPath
// resizes this cell correctly
if(shouldReloadData) {
NSInteger imageWidth = image.size.width;
NSInteger imageHeight = image.size.height;
if(imageWidth > [ColumnController columnWidth]) {
float ratio = [ColumnController columnWidth] / imageWidth;
imageWidth = ratio * imageWidth;
imageHeight = ratio* imageHeight;
}
if(imageHeight > 1024) {
float ratio = 1024 / imageHeight;
imageHeight = ratio * imageHeight;
imageWidth = ratio* imageWidth;
}
self.images[dataForThisCell[@"name"]] = @{ @"width": @(imageWidth), @"height": @(imageHeight), @"titleHeight": @([post heightOfGivenText: dataForThisCell[@"title"]]) };
[self.tableView reloadData];
// otherwise we alreaady knew the dimensions of this image so we can assume
// that heightForRowAtIndexPath has already calculated the correct height
// for this cell
}else{
// assign the image we downloaded to the UIImageView within the cell
cell.preview.image = image;
// position the image
NSInteger width = [self.images[dataForThisCell[@"name"]][@"width"] integerValue];
NSInteger height = [self.images[dataForThisCell[@"name"]][@"height"] integerValue];
cell.preview.frame = CGRectMake( ([ColumnController columnWidth] - width)/2 , [self.images[dataForThisCell[@"name"]][@"titleHeight"] integerValue] + 10, width, height);
}
}
failure: ^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {}];
}
// set title of the cell
cell.title.text = [NSString stringWithFormat: @"%@\n\n\n\n\n", dataForThisCell[@"title"]];
`enter code here`// ask for a restyle
[cell setNeedsLayout];
// returns my customized cell
return cell;
}
发生的事情是一切都按照我想要的方式工作,但是一旦我向下滚动超过大约 100 个单元格左右,我的应用程序的背景就会变黑几秒钟,然后我看到我的主屏幕(我见过一些人称之为HSOD - 死亡主屏幕)。有时在 xcode 的控制台中,我会在崩溃前看到内存警告,有时却没有。
我知道一个事实,无论问题是什么,它都与将图像放入单元格有关。如果我只注释掉这一行:
cell.preview.image = image;
然后一切正常,不再崩溃(但当然图像不会显示在单元格中)。
单元格正在被重用,我知道这是有效的,我将 UIImageView 的图像属性设置为 nil:
- (void) prepareForReuse {
[super prepareForReuse];
if(self.preview != nil)
self.preview.image = nil;
}
在我的 appDelegate 中,我还定义了这个:
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[UIImageView clearAFImageCache];
}
这会删除图像缓存,但这也不能解决问题(无论如何iOS应该在内存警告时自动清除图像缓存)。
我对我的项目运行了分析,它报告没有内存泄漏,这是分析器显示的,以及显示崩溃时的分配:
除了控制台中出现大约 2/3 的应用程序崩溃时间的偶尔内存警告外,控制台中没有出现其他错误,并且我没有遇到任何断点或异常。