Geflieste PDF-Ansicht führt zu Speicherverlust (nicht ARC) - ios, objective-c, Speicherlecks, cgpdfdocument, cgpdf

Also arbeite ich an einem sehr großen und sehr alten Legacy-Projekt, das vor etwa 5 Jahren in nicht-ARC-Ziel-C-Code codiert wurde. Ich habe von den vorherigen Entwicklern übernommen und muss dieses Biest nun pflegen.

Die App ermöglicht Benutzern das Lesen von PDF-Seitenals separate Dateien heruntergeladen. Das Problem ist, dass die Ansicht, in der die PDFs auf dem Bildschirm angezeigt werden, zu einem Speicherverlust führt. Ein einfaches Paging für etwa 5 Minuten führt zu etwa 400 MB Speicherverbrauch.

Beim Profiling der App habe ich also die Codezeile entdeckt, die das Problem zu sein scheint. Der vorherige Entwickler hat sogar einen Kommentar hinterlassen: "TODO DANNY leckt hier 100%" ... Danke Danny ...

Jedenfalls habe ich viele Dinge und für das Leben ausprobiertvon mir kann nicht verstehen, warum das Speicherleck ist. Die meisten meiner Arbeit und Erfahrung ist mit ARC-Projekten, so dass ich kämpfen, um zu verstehen, warum dieser Code undicht ist.

Die UIView-Subview-Klasse sieht folgendermaßen aus:

- (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);
}
}

Jede Hilfe wird sehr geschätzt!

Danke im Voraus, Eish

Antworten:

1 für die Antwort № 1

Also habe ich es geschafft, das Problem zu lösen.

Das Problem war nicht mit dem Code, den ich oben eingefügt habe(Entschuldigung für die Irreführung), das Problem war, dass in der Dealloc-Methode der Parent-View der vorherige Entwickler die flowedPDF-Views nicht aus der Superview löschte und die Variable nach dem Aufruf der Release nicht auf nil setzte.

Ich entdeckte dies, indem ich einen NSLog in die Dealloc-Methode einfügte und sah, dass die Elternansicht die Zuordnung aufhob, aber die 2 Unterteilungen mit gekachelten PDFs wurden nicht freigegeben.

Nachdem Sie sie aus dem Superview entfernt und die Variablen auf null gesetzt haben, wurden beide Dealloc-Methoden ausgelöst und die App-Speicherauslastung steigt nicht permanent an, während Sie die Seite aufrufen!


Speisekarte