Плиточный просмотр PDF пропускает память (не ARC)
Поэтому я работаю над очень большим и очень старым унаследованным проектом, который был закодирован около 5 лет назад в нецелевом коде c ARC. Я перенял у предыдущих разработчиков и теперь должен поддерживать этого зверя.
Приложение позволяет пользователям читать страницы PDF, которые загружаются в виде отдельных файлов. Проблема заключается в том, что PDF-файлы, отображаемые на экране, плохо просачиваются в память. Простое разбиение на страницы в течение 5 минут приводит к потреблению около 400 мегабайт памяти.
Поэтому при профилировании приложения я обнаружил строку кода, которая, похоже, является проблемой. Предыдущий разработчик даже оставил комментарий: "TODO DANNY просачивается сюда на 100%"... Спасибо, Дэнни...
Во всяком случае, я перепробовал много вещей, и на всю жизнь я не могу понять, почему это утечка памяти. Большая часть моей работы и опыта связана с проектами ARC, поэтому я изо всех сил пытаюсь понять, почему этот код протекает.
Класс подпредставления UIView выглядит следующим образом:
- (void)dealloc {
self.pauseDraw = YES;
CGPDFPageRelease(pdfPage);
CGPDFDocumentRelease(pdfDocumentRef);
[super dealloc];
}
- (id)initWithFrame:(CGRect)frame andScale:(CGFloat)scale{
if ((self = [super initWithFrame:frame])) {
CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
if ([[[UIDevice currentDevice] modelName] isEqualToString:@"iPad 3G"]) {
tiledLayer.tileSize = CGSizeMake(1024, 1024);
tiledLayer.levelsOfDetail = 4;
tiledLayer.levelsOfDetailBias = 4;
} else {
tiledLayer.levelsOfDetail = 4;
tiledLayer.levelsOfDetailBias = 4;
tiledLayer.tileSize = CGSizeMake(2048, 2048);
}
myScale = scale;
}
return self;
}
+ (Class)layerClass {
return [CATiledLayer class];
}
- (void)setPage:(CGPDFPageRef)newPage andDocument:(CGPDFDocumentRef)docRef {
CGPDFPageRelease(pdfPage);
CGPDFDocumentRelease(pdfDocumentRef);
self->pdfPage = CGPDFPageRetain(newPage);
self->pdfDocumentRef = CGPDFDocumentRetain(docRef);
}
- (void) releasePDFsFromMemory {
CGPDFPageRelease(pdfPage);
CGPDFDocumentRelease(pdfDocumentRef);
}
-(void)drawRect:(CGRect)r {}
-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context {
if(!self.superview){
return;
}
if (pauseDraw) {
return;
}
@autoreleasepool {
CGRect cropBox = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);
int rotate = CGPDFPageGetRotationAngle(pdfPage);
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0, 0);
CGContextScaleCTM(context, myScale, myScale);
switch (rotate) {
case 0:
CGContextTranslateCTM(context, 0, cropBox.size.height);
CGContextScaleCTM(context, 1, -1);
break;
case 90:
CGContextScaleCTM(context, 1, -1);
CGContextRotateCTM(context, -M_PI / 2);
break;
case 180:
case -180:
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, cropBox.size.width, 0);
CGContextRotateCTM(context, M_PI);
break;
case 270:
case -90:
self.frame = CGRectMake(0, 0, 768, 1004);
CGContextTranslateCTM(context, cropBox.size.height, cropBox.size.width);
CGContextRotateCTM(context, M_PI / 2);
CGContextScaleCTM(context, -1, 1);
break;
}
CGRect clipRect = CGRectMake(0, 0, cropBox.size.width, cropBox.size.height);
CGContextAddRect(context, clipRect);
CGContextClip(context);
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(context, clipRect);
CGContextTranslateCTM(context, -cropBox.origin.x, -cropBox.origin.y);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
// TODO DANNY leak here 100% ->
CGContextDrawPDFPage(context, pdfPage);
CGContextRestoreGState(context);
}
}
Любая помощь будет высоко ценится!
Заранее спасибо Eish
1 ответ
Так что мне удалось решить проблему.
Проблема была не в коде, который я вставил выше (извините за ввод в заблуждение), проблема была в том, что в методе dealloc родительского представления предыдущий разработчик не удалял представления tiledPDF из суперпредставления и не устанавливал переменную равной nil после вызова release,
Я обнаружил это, поместив NSLog в метод dealloc и увидел, что родительское представление было освобождено, но 2-плиточные PDF-подпредставления вообще не были освобождены.
После удаления их из суперпредставления и установки переменных в nil оба метода dealloc были запущены, и использование памяти приложением не увеличивается постоянно, когда вы просматриваете страницу!