Выделение памяти и освобождение для UIImage в iPhone? - PullRequest
6 голосов
/ 07 октября 2009

Я использую следующий код в 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;
}

Я использую следующую строку кода в cellForRowAtIndexPath, чтобы обновить изображение ячейки:

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

Теперь, когда я добавляю это табличное представление и извлекаю его из контроллера навигации, я вижу скачок памяти. Я не вижу утечек, но память продолжает расти.

Обратите внимание, что изображения меняются для каждой строки, и я создаю контроллер с помощью отложенной инициализации, то есть я создаю или выделяю его всякий раз, когда он мне нужен.

Я видел в интернете много людей, сталкивающихся с той же проблемой, но очень редкими хорошими решениями. У меня несколько представлений, использующих один и тот же способ, и я вижу, что объем памяти увеличился до 4 МБ за 20-25 переходов между представлениями.

Какое хорошее решение для решения этой проблемы.

Тпй.

Ответы [ 5 ]

1 голос
/ 27 октября 2010

В зависимости от размера изображений использование imageNamed: может быть причиной увеличения объема памяти. Это не обязательно проблема. imageNamed: предназначен для использования кодом, который часто загружает одни и те же изображения и поддерживается кешем. В iOS 3.0 были утечки, но они были исправлены, и я не знаю каких-либо причин не использовать этот API, если вы хотите воспользоваться преимуществами кэширования.

Вы должны запустить свой код через инструменты, в частности шаблон Leaks. С помощью анализа heapshot вы можете определить места в своем коде, которые увеличивают объем памяти, когда вы этого не ожидаете, даже если они пропущены при традиционном анализе утечек. Билл Бумгарнер написал сообщение , в котором обсуждается использование анализа снимков кучи. В качестве примера он использует приложение Mac OS X, но методы одинаково хорошо применимы и к приложениям iOS.

1 голос
/ 26 октября 2010

[UIImage imageNamed:] вызывает утечки памяти, потому что используется внутреннее кэширование изображений.

  • Простой метод - кэшировать изображение внешне программистом.
    Для этого используйте -(UIImage*)thumbnailImage:(NSString*)fileName { UIImage *thumbnail = [thumbnailCache objectForKey:fileName]; if (nil == thumbnail) {<br> 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; }

    Объявить NSMutableDictionary *thumbnailCache; в файле .h

    И использовать можно использовать эту функцию, как

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

  • Очистить общий кэш приложения, т.е. установить nil

Я думаю, что это решит вашу проблему.

1 голос
/ 07 октября 2009

Вы не можете вернуться из процедуры до того, как вы EndImageContext:

return UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Попробуйте это:

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

Вам не нужны закомментированные записи или авто-релизы.

0 голосов
/ 28 октября 2010

Не решает проблему, но может сделать ее не проблемой: кэшируйте ваши миниатюры. В 36 х 36 они будут очень маленькими, чтобы их можно было сохранить в памяти. Это также должно повысить производительность, поскольку графическая работа довольно интенсивна.

0 голосов
/ 20 мая 2010

Вместо использования autorelease для управления памятью (которая, насколько я знаю, не дает или почти не дает никаких гарантий относительно , когда память будет освобождена, просто это в конечном итоге будет разделено) Разложите строку кода на три части и управляйте памятью самостоятельно. В лучшем случае это может быть все, что необходимо для устранения утечек памяти. По крайней мере, такой инструмент, как Instruments, сможет взять его оттуда и показать, откуда возникают возможные утечки памяти.

Кроме того, [UIImage imageNamed:] может быть дорогим и автоматически выпускает изображение. Вы можете заменить этот вызов относительно простым механизмом кэширования изображений, который может повторно использовать часто запрашиваемые образы и повысить производительность при загрузке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...