У меня есть этот простой UITableView, и каждая ячейка имеет соответствующее ему изображение. Все, что я делаю, это отображение названия для изображения и самого изображения в каждой ячейке. Вот мой cellForRowAtIndexPath:UITableView с образами сбоев изображений при прокрутке вниз
- (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 к нулю:
- (void) prepareForReuse {
[super prepareForReuse];
if(self.preview != nil)
self.preview.image = nil;
}
и в моем AppDelegate я также определить это:
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[UIImageView clearAFImageCache];
}
Который удаляет кеш изображения, но это также не устраняет проблему (и, в любом случае, iOS должна автоматически очищать кэши изображений от предупреждений памяти).
Я провел анализ на мой проект, и он не сообщает, отсутствие утечек памяти, а вот профайлер, показывающий, что, а также с указанием распределения в момент аварии:
Другие, чем случайное предупреждение о памяти в консоли, которое появляется примерно в 2/3 раза в момент сбоя приложения, никаких других ошибок, появляющихся на консоли, нет, и я не ударяю ни о каких контрольных точках или исключениях.
Я не думаю, что это причина. Кажется, что они переработаны - я поставил NSLog в оператор if, и он работает только 7 раз. – Macmee
Хорошо, тогда это проблема с вашим блоком 'success'. Я бы рекомендовал отображать изображения в ячейках по размеру вашего заполнителя (при необходимости масштабируется с использованием режима заполнения аспект). Не рекомендуется ссылаться на 'self' и манипулировать ячейкой таблицы так, как вы это делаете. – mattt
Я изменил его на этот http://pastebin.com/seBsBZ7j, и он по-прежнему падает после получения 2 предупреждений памяти. – Macmee