Проблема dealloc'ing память используется UIImageViews с довольно большим изображением в UIScrollView

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

tooltip="{{recentDate | date: 'medium'}}" // Using interpolation

или

[tooltip]="recentDate | date: 'medium'" // Data binding
11
задан Bdebeez 14 November 2008 в 13:38
поделиться

7 ответов

Я решил тайну - и я вполне уверен, это - ошибка на стороне Apple.

Как Kendall, предложенный (Спасибо!), проблема заключается в том, как InterfaceBuilder загружает изображения из файла NIB. Когда Вы initFromNib, весь UIImageViews будет init с UIImage использование imageNamed: метод UIImage. Этот вызов использование, кэширующееся для изображения. Обычно, это - то, что Вы хотите. Однако с очень большими изображениями и дополнительно, которые прокручивают далеко видимой области, это, кажется, не повинуется предупреждениям памяти и не выводит этот кэш. Это - то, чему я верю, чтобы быть ошибкой на стороне Apple (прокомментируйте, соглашаетесь ли Вы/не соглашаетесь - я хотел бы отправить это, если другие соглашаются). Как я сказал выше, память, используемая этими изображениями, действительно кажется, освобождена, если пользователь прокручивает вокруг достаточно для создания всего этого видимым.

Обходное решение, которое я нашел (также предложение Kendall) должно оставить название картинки, незаполненное в файле NIB. Таким образом, Вы размечаете свои элементы UIImageView как нормальные, но не выбираете изображение. Затем в Вашем коде viewDidLoad, Вы входите и загружаете изображение с помощью imageWithContentsOfFile: вместо этого. Этот метод НЕ кэширует изображение и поэтому не вызывает проблем памяти с сохранением больших изображений.

Конечно, imageNamed: намного легче использовать, потому что это принимает значение по умолчанию к чему-либо в пакете, вместо того, чтобы иметь необходимость найти путь. Однако можно получить путь к пакету со следующим:

NSString *fullpath = [[[NSBundle mainBundle] bundlePath];

Помещение, что все вместе, вот то, на что это похоже в коде:

NSString *fullpath = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:[NSString stringWithFormat:@"/%@-%d.png", self.nibName, imageView.tag]];
UIImage *loadImage = [UIImage imageWithContentsOfFile:fullpath];
imageView.image = loadImage;

Так добавляя, что к моему коду выше, полная функция похожа на это:

- (CGFloat)findHeight 
{
    UIImageView *imageView = nil;
    NSArray *subviews = [self.scrollView subviews];

    CGFloat maxYLoc = 0;
    for (imageView in subviews)
    {
        if ([imageView isKindOfClass:[UIImageView class]])
        {
            CGRect frame = imageView.frame;

            if ((frame.origin.y + frame.size.height) > maxYLoc) {
                maxYLoc  = frame.origin.y;
                maxYLoc += frame.size.height;
            }

            NSString *fullpath = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:[NSString stringWithFormat:@"/%@-%d.png", self.nibName, imageView.tag]];
            NSLog(fullpath);


            UIImage *loadImage = [UIImage imageWithContentsOfFile:fullpath];
            imageView.image = loadImage;
        }
    }
    return maxYLoc;
}
15
ответ дан 3 December 2019 в 04:34
поделиться

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

Вы могли попытаться загрузить все изображения imageWithContentsOfFile:, или imageWithData: и посмотрите, ведет ли это себя то же (притягивающий незаполненный UIImageViews в IB и контенте установки в viewDidLoad:).

Читайте UIImage ссылка класса, если Вы хотели бы немного больше детали, это также, описывает, какие методы кэшируются.

Если бы это - кэш, это, вероятно, в порядке, хотя, поскольку система освободила бы его в случае необходимости (Вы также пытались поразить Моделировать Предупреждение Памяти в средстве моделирования?)

4
ответ дан 3 December 2019 в 04:34
поделиться
- (void)dealloc {
    NSLog(@"DAY Controller Dealloc'd");
    [self.scrollView release];
    [super dealloc];
}

дайте этому выстрел, Ваш @property (), определение запрашивает это быть сохраненным, но Вы явно не выпускали объект

0
ответ дан 3 December 2019 в 04:34
поделиться

Из того, что я учился на его поведении управления памятью, то, что представления не получат dealloc, если не низкий в памяти. Попробуйте официальную демонстрацию как SQLBooks: 1. Выполненный с Монитором Утечек 2. Пробегите каждый представления, которые это имеет. 3. Вернитесь к корневому представлению. 4. Вы заметите, что уровень использования памяти является все еще тем же. Поскольку Kendall сказал, что это может кэшироваться?

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

0
ответ дан 3 December 2019 в 04:34
поделиться

Известная проблема - утечка памяти в imageName. Я нашел для этого действительно полезное решение - создание наличных изображений в делегате приложения, таким образом оптимизируя производительность и использование памяти в моем приложении. См. Это сообщение в блоге

0
ответ дан 3 December 2019 в 04:34
поделиться

Отдельно из ваших проблем с кешированием imageNamed, ответ на ваш вопрос

У меня есть большой UIScrollView, в который Ставлю 3-4 довольно больших (320x1500 пикселей или около того) плитки изображения UIImageView. [...] Есть ли проблемы с использованием изображения такого размера?

Находится в заголовке документации UIImage:

You should avoid creating UIImage objects that are greater than 1024 x 1024 in size.
Besides the large amount of memory such an image would consume, you may run into 
problems when using the image as a texture in OpenGL ES or when drawing the image 
to a view or layer.

Кроме того, Apple утверждает, что исправила проблему очистки кэша imageNamed в версии 3.0 и более поздних версиях, хотя я сам не тестировал это тщательно.

4
ответ дан 3 December 2019 в 04:34
поделиться

Завершение ответа Bdebeez.

Хорошая идея - переопределить imageNamed: , вызывая imageWithContentsOfFile: .

Вот идея кода:

@implementation UIImage(imageNamed_Hack)

+ (UIImage *)imageNamed:(NSString *)name {

    return [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] bundlePath], name ] ];
}

@end

Примечание: С этим переопределением у вас не будет никаких UIImages, загружающих кеш, если вам это нужно, вам придется реализовать свой собственный кеш.

1
ответ дан 3 December 2019 в 04:34
поделиться