I am trying to give the user the option to edit hue and brightness using a couple sliders that use CIFilters to affect the image in a UIImageView.

I have it working pretty well, but with one issue: if the sliders are used too much, memory warnings start popping up, and then, if the user keeps on trying after that, the app quits, but there isn't a crash log (??? super confused by this).

I'm still pretty new to programming, and especially new to memory management, but hopefully someone here can help.

Here's my code:

In my .h file:

@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;

And I also have an instance BOOL defined called "imageFilterUpdating"

Here are the relevant parts of the .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;
}

Can anyone help me clear out memory more efficiently so the user can use the sliders infinitely? This code all works fine otherwise.

I've tried to alloc/init things where ever I can, as I've read in a lot of places that ARC deals with that a whole lot better than using things like [UIImage imageNamed:@""], and it seems to have helped some, but the app still crashes after a lot of editing. I've also started reusing instance variables, rather than create new variables every time the method is run, which also seems to help, but it's not 100%.

The UISliders are set to be continuous, and that's something I'd prefer not to change.

Thanks

有帮助吗?

解决方案

Every time you run [ccontext createCGImage:outputImage fromRect:outputImage.extent] you're creating a CGImageRef that isn't released automatically and isn't managed by ARC. Pull that out into its own variable and release it with CGImageRelease() after you create editedInputImage.

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

其他提示

It looks like you aren't disposing of the various images you create. You need to release editedInputImage at the least.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top