2009-10-07 14 views
6

Sto usando il codice seguente in iPhone a diminuire immagine ritagliata come segue:allocazione di memoria e rilascio per UIImage in iPhone?

- (UIImage*) getSmallImage:(UIImage*) img 
{ 
    CGSize size = img.size; 
    CGFloat ratio = 0; 
    if (size.width < size.height) { 
     ratio = 36/size.width; 
    } else { 
     ratio = 36/size.height; 
    } 
    CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height); 

    UIGraphicsBeginImageContext(rect.size); 
    [img drawInRect:rect]; 

    UIImage *tempImg = [UIGraphicsGetImageFromCurrentImageContext() retain]; 

    UIGraphicsEndImageContext(); 
    return [tempImg autorelease]; 
} 

- (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect 
{ 

    //create a context to do our clipping in 
    UIGraphicsBeginImageContext(rect.size); 
    CGContextRef currentContext = UIGraphicsGetCurrentContext(); 

    //create a rect with the size we want to crop the image to 
    //the X and Y here are zero so we start at the beginning of our 
    //newly created context 

    CGFloat X = (imageToCrop.size.width - rect.size.width)/2; 
    CGFloat Y = (imageToCrop.size.height - rect.size.height)/2; 


    CGRect clippedRect = CGRectMake(X, Y, rect.size.width, rect.size.height); 
    //CGContextClipToRect(currentContext, clippedRect); 



    //create a rect equivalent to the full size of the image 
    //offset the rect by the X and Y we want to start the crop 
    //from in order to cut off anything before them 
    CGRect drawRect = CGRectMake(0, 
           0, 
           imageToCrop.size.width, 
           imageToCrop.size.height); 

    CGContextTranslateCTM(currentContext, 0.0, drawRect.size.height); 
    CGContextScaleCTM(currentContext, 1.0, -1.0); 
    //draw the image to our clipped context using our offset rect 
    //CGContextDrawImage(currentContext, drawRect, imageToCrop.CGImage); 


    CGImageRef tmp = CGImageCreateWithImageInRect(imageToCrop.CGImage, clippedRect); 

    //pull the image from our cropped context 
    UIImage *cropped = [UIImage imageWithCGImage:tmp];//UIGraphicsGetImageFromCurrentImageContext(); 
    CGImageRelease(tmp); 
    //pop the context to get back to the default 
    UIGraphicsEndImageContext(); 

    //Note: this is autoreleased*/ 
    return cropped; 
} 

Sto usando seguente riga di codice in cellForRowAtIndexPath per aggiornare l'immagine della cella:

cell.img.image = [self imageByCropping:[self getSmallImage:[UIImage imageNamed:@"goal_image.png"]] toRect:CGRectMake(0, 0, 36, 36)]; 

Ora, quando Aggiungo questa vista tabella e la apro dal controller di navigazione, vedo un aumento della memoria. Non vedo perdite ma la memoria continua a salire.

Si noti che le immagini cambiano per ogni riga e sto creando il controller utilizzando l'inizializzazione pigra che creo o lo assegno ogni volta che ne ho bisogno.

Ho visto su Internet molte persone che affrontano lo stesso problema, ma soluzioni molto rare. Ho più viste che usano allo stesso modo e vedo quasi memoria aumentata a 4 MB entro 20-25 transizioni di visualizzazione.

Qual è la soluzione migliore per risolvere questo problema.

tnx.

risposta

1

Non è possibile tornare dalla routine prima di EndImageContext:

return UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 

Prova questa:

UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 
return newImage; 

Non è necessario la conserva o autoreleases che sono commentate.

+0

Ho provato, ma ancora non risolve il problema. Vedo ancora gli aumenti della memoria. – rkb

-1

Invece di usare autorelease per gestire la memoria (che, per quanto ne so, ha poca o nessuna garanzia circa quando sarà rilasciato di memoria, solo che alla fine) dividere il caso d'uso riga di codice in tre parti e gestisci la memoria da solo. Nel migliore dei casi questo potrebbe essere tutto ciò che è necessario per risolvere le perdite di memoria. Per lo meno uno strumento come Instruments sarà in grado di prenderlo da lì e mostrarti da dove vengono generate le perdite di memoria.

Inoltre, [UIImage imageNamed:] può essere costoso e autorizzare l'immagine. È possibile sostituire quella chiamata con un meccanismo di memorizzazione nella cache delle immagini relativamente semplice che potrebbe riutilizzare le immagini richieste comunemente e ottenere un aumento delle prestazioni all'avvio.

+2

Hai ragione che nulla garantisce quando un oggetto autoreleased viene effettivamente rilasciato, ma praticamente il thread principale drena il suo pool autorelease alla fine di ogni ciclo di esecuzione. Anche il tuo consiglio riguardo a 'imageNamed:' è obsoleto. Mentre c'erano problemi con esso prima di iOS 3.0, sono stati risolti. –

1

[UIImage imageNamed:] causa perdite di memoria perché ha utilizzato il caching interno delle immagini.

  • Il metodo semplice consiste nel memorizzare l'immagine esternamente dal programmatore.
    Per questo, utilizzare -(UIImage*)thumbnailImage:(NSString*)fileName { UIImage *thumbnail = [thumbnailCache objectForKey:fileName]; if (nil == thumbnail) {
    NSString *thumbnailFile = [NSString stringWithFormat:@"%/%@", [[NSBundle mainBundle] pathForResource:fileName ofType:@"png"]]; //dont forget to set correct image type thumbnail = [UIImage imageWithContentsOfFile:thumbnailFile]; [thumbnailCache setObject:thumbnail forKey:fileName]; } return thumbnail; }

    Dichiarare NSMutableDictionary *thumbnailCache; in.h di file

    E l'uso possono utilizzare questa funzione come

    cell.img.image = [self imageByCropping:[self getSmallImage:[self thumbnailImage:@"goal_image"]] toRect:CGRectMake(0, 0, 36, 36)];

  • Cancella l'applicazione condivisa di cache cioè impostare a zero

Penso che questo risolverà ur problema.

+0

I problemi con 'imageNamed:' sono stati risolti in iOS 3.0. –

+0

Penso No perché ho riscontrato il problema in iOS3.2 quando ho eseguito l'applicazione iPad DMA2010 –

1

A seconda della dimensione delle immagini, l'utilizzo di imageNamed: potrebbe essere responsabile della crescita della memoria. Questo non è necessariamente un problema. imageNamed: è pensato per essere utilizzato dal codice che carica frequentemente le stesse immagini ed è supportato da una cache. Ci sono state perdite in esso prima di iOS 3.0, ma sono stati corretti e non sono a conoscenza di alcun motivo per non utilizzare questa API se si desidera sfruttare la memorizzazione nella cache.

È necessario eseguire il codice tramite Strumenti, in particolare il modello di perdite. Utilizzando l'analisi heapshot, è possibile individuare i punti nel codice che aumentano l'impronta di memoria quando non ci si aspetta, anche se vengono persi dall'analisi tradizionale delle perdite. Bill Bumgarner wrote a post discutendo l'uso dell'analisi heapshot. Per il suo esempio usa un'applicazione Mac OS X, ma le tecniche si applicano altrettanto bene alle app iOS.

0

Non risolve il problema, ma potrebbe renderlo un non-problema: memorizza le miniature. A 36 x 36 saranno molto piccoli da tenere in memoria. Ciò dovrebbe anche fornire un miglioramento delle prestazioni in quanto il lavoro grafico è piuttosto intenso.