UISlider и CIFilter вызывают сбой приложения после чрезмерного использования

Я пытаюсь дать пользователю возможность редактировать оттенок и яркость, используя пару ползунков, которые используют CIFilters для воздействия на изображение в UIImageView.

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

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

Вот мой код:

В моем файле .h:

@property (weak, nonatomic) IBOutlet UISlider *hueSlider;
@property (weak, nonatomic) IBOutlet UISlider *brightnessSlider;

@property (weak, nonatomic) CIImage *outputImage;
@property (strong, nonatomic) CIFilter *hueFilter;
@property (strong, nonatomic) CIFilter *brightnessFilter;
@property (strong, nonatomic) CIContext *ccontext;
@property (strong, nonatomic) CIImage *inputImage;

- (IBAction)hueValueChangedAction:(id)sender;
- (IBAction)brightnessValueChangedAction:(id)sender;

И у меня также есть экземпляр BOOL, определенный под названием «imageFilterUpdating».

Вот соответствующие части .m:

- (IBAction)hueValueChangedAction:(id)sender {
    if (!imageFilterUpdating) {
        [self performSelectorInBackground:@selector(sliderValueChanged) withObject:nil];
    }
}

- (IBAction)brightnessValueChangedAction:(id)sender {
    if (!imageFilterUpdating) {
        [self performSelectorInBackground:@selector(sliderValueChanged) withObject:nil];
    }
}

- (void)sliderValueChanged {
    imageFilterUpdating = YES;

    if (inputImage == nil)
        inputImage = [[CIImage alloc] initWithImage:self.imageWithoutOverlayView.image];

    if (brightnessFilter == nil) {
        brightnessFilter = [CIFilter filterWithName:@"CIExposureAdjust"];
        [brightnessFilter setDefaults];
        [brightnessFilter setValue: inputImage forKey: @"inputImage"];
    }

    [brightnessFilter setValue: [NSNumber numberWithFloat:self.brightnessSlider.value] forKey: @"inputEV"];

    [self setOutputImage:[brightnessFilter valueForKey: @"outputImage"]];

    if (ccontext == nil)
        ccontext = [CIContext contextWithOptions:nil];

    CIImage *editedInputImage = [[CIImage alloc] initWithCGImage:[ccontext
                                                              createCGImage:outputImage
                                                              fromRect:outputImage.extent]];

    if (hueFilter == nil) {
        hueFilter = [CIFilter filterWithName:@"CIHueAdjust"];
        [hueFilter setDefaults];
    }
    [hueFilter setValue: editedInputImage forKey: @"inputImage"];
    [hueFilter setValue: [NSNumber numberWithFloat:self.hueSlider.value] forKey: @"inputAngle"];

    [self setOutputImage:[hueFilter valueForKey: @"outputImage"]];

    UIImage *endImage = [[UIImage alloc] initWithCGImage:[ccontext
                                                      createCGImage:outputImage
                                                      fromRect:outputImage.extent]];
    self.imageWithoutOverlayView.image = endImage;

    [self setOutputImage:nil];
    imageFilterUpdating = NO;
}

- (void)didReceiveMemoryWarning {
    self.brightnessSlider.enabled = NO;
    self.hueSlider.enabled = NO;
    [super didReceiveMemoryWarning];

    while (imageFilterUpdating); // this is because if you set the other parts nil in the middle of updating the image filter, the app crashes
    [self setHueFilter:nil];
    [self setBrightnessFilter:nil];
    [self setCcontext:nil];
    [self setOutputImage:nil];
    self.brightnessSlider.enabled = YES;
    self.hueSlider.enabled = YES;
}

Может ли кто-нибудь помочь мне более эффективно очистить память, чтобы пользователь мог бесконечно использовать ползунки? В противном случае этот код работает нормально.

Я пытался выделять/инициализировать вещи, где только мог, так как я читал во многих местах, что ARC справляется с этим намного лучше, чем с использованием таких вещей, как [UIImage imageNamed: @""], и кажется, Некоторым помогло, но приложение все равно вылетает после долгого редактирования. Я также начал повторно использовать переменные экземпляра, а не создавать новые переменные каждый раз при запуске метода, что также помогает, но не на 100%.

UISliders настроены на непрерывную работу, и я бы предпочел не менять это.

Спасибо


person user1698766    schedule 26.09.2012    source источник


Ответы (2)


Каждый раз, когда вы запускаете [ccontext createCGImage:outputImage fromRect:outputImage.extent], вы создаете CGImageRef, который не выпускается автоматически и не управляется ARC. Вытащите это в свою собственную переменную и отпустите с помощью CGImageRelease() после создания editedInputImage.

CGImageRef tempImage = [ccontext createCGImage:outputImage fromRect:outputImage.extent];
CIImage *editedInputImage = [[CIImage alloc] initWithCGImage:tempImage];
CGImageRelease(tempImage);
person Jon Shier    schedule 26.09.2012

Похоже, вы не избавляетесь от различных изображений, которые создаете. Вам нужно как минимум освободить editedInputImage.

person user1118321    schedule 26.09.2012
comment
Я использую автоматический подсчет ссылок, поэтому выпуск вещей должен выполняться автоматически (на самом деле я получаю сообщение об ошибке в Xcode, если пытаюсь что-то выпустить самостоятельно). - person user1698766; 26.09.2012
comment
Ах, я неправильно понял, что вы написали об ARC. Извини за это. Вы запускали инструмент утечки? - person user1118321; 26.09.2012
comment
Я только что сделал. Категория CFData (хранилище) заполняется довольно быстро, когда я перемещаю ползунки, и не перемещается в противном случае. Я гуглил об этом, но пока ничего не придумал, чтобы решить мою проблему. - person user1698766; 26.09.2012
comment
Это должно дать вам трассировку стека, чтобы вы могли видеть, откуда он исходит. Что говорит трассировка стека? - person user1118321; 26.09.2012