【问题标题】:App Crashes when trying to update a UIImageView after modifying the RGB values for an iOS project修改 iOS 项目的 RGB 值后尝试更新 UIImageView 时应用程序崩溃
【发布时间】:2012-05-26 17:05:30
【问题描述】:

我正在尝试对图像应用多种效果。我创建了一个单独的文件来处理我可以发送UIImageView 并接收修改后的副本的效果处理。为了节省处理时间,我首先将图像加载到单独的处理文件中并存储在内存中,而不是每次要修改时都加载图像。流程是 getImageData -> modifyRGB -> displayImage。一切正常,直到最后一步。返回的修改后的图像会在屏幕上显示片刻,然后 Xcode 崩溃并出现 EXEC_BAD_ACCESS:code 1 错误。我反复检查代码,找不到问题。任何帮助是极大的赞赏。谢谢!

更新更多信息

我正在使用带有自动引用计数的 Xcode 4.3.1

使用换行符,我可以验证在执行 self.imageView.image = [self.imageManipulation displayImage]; 行时发生崩溃。图像已更新,但随后程序立即崩溃。 使用 NSZombie,我得到一个错误 -[Not A Type retain]: message sent to deallocated instance 0x2cceaf80

从我使用的 viewController 中:

[self.imageManipulation getImageData:self.imageView.image];
[self.imageManipulation modifyRGB];
self.imageView.image = [self.imageManipulation displayImage];

我的 ImageManipulation 文件包括:

@implementation ImageManipulation
static unsigned char *rgbaDataOld;
static unsigned char *rgbaDataNew;
static int width;
static int height;

- (void)getImageData:(UIImage *)image
{
    CGImageRef imageRef = [image CGImage];

    width = CGImageGetWidth(imageRef);
    height = CGImageGetHeight(imageRef);

    rgbaDataOld = malloc(height * width * 4);
    rgbaDataNew = malloc(height * width * 4);

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    CGContextRef context = CGBitmapContextCreate(rgbaDataOld, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);

    CGColorSpaceRelease(colorSpace);
    CGContextRelease(context);
    CGImageRelease(imageRef);
}

//modify rgb values 
- (void)modifyRGB
{
    for (int byteIndex = 0 ; byteIndex < width * height * 4; byteIndex += 4)
    {
        rgbaDataNew[byteIndex] = (char) (int) (rgbaDataOld[byteIndex] / 3) + 1;
        rgbaDataNew[byteIndex+1] = (char) (int) (rgbaDataOld[byteIndex+1] / 3 + 1);
        rgbaDataNew[byteIndex+2] = (char) (int) (rgbaDataOld[byteIndex+2] / 3) + 1;
        rgbaDataNew[byteIndex+3] = (char) (int) 255;
    }    
}

//set image
- (UIImage *)displayImage
{
    CGContextRef context;

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    context = CGBitmapContextCreate(rgbaDataNew, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast ); 

    CGImageRef imageRef = CGBitmapContextCreateImage (context);
    UIImage *outputImage = [UIImage imageWithCGImage:imageRef];  

    CGColorSpaceRelease(colorSpace);    
    CGContextRelease(context);  
    CGImageRelease(imageRef);
    return outputImage;
}

@end

【问题讨论】:

  • 一般情况下Excess_Bad_Access是在你访问被释放的数据或者对象没有引用它的时候出现。检查你的代码分配和释放对象,异常就出现了。
  • 很遗憾你的问题太宽泛了。您是否设置了一些断点以在抛出错误时缩小范围?您是否在 Debug Navigator 中将线程列表压缩滑块一直滑动到右侧以在抛出异常时查看更大的堆栈块,或者在 lldb 中键入“bt”(用于“backtrace”)(或gdb)控制台?正如 roronoa 所说,这可能是由于试图访问已经发布的内容,但一些基本的调试来缩小范围会为您解答或至少给我们足够的线索来帮助。
  • 我会尝试进一步缩小范围。执行 self.imageView.image = [self.imageManipulation displayImage]; 行时发生崩溃。而且,即使它在那条线上崩溃,仍然显示变暗的修改图像,但仅在崩溃前的一瞬间。 [self.imageManipulation displayImage] 方法完全执行 - 使用断点验证。我会继续检查。
  • 您似乎正确使用了 imageWithCGImage ...您的 imageView 是否没有以某种方式保留?您是否在跟踪中得到任何信息?
  • 不确定。这是跟踪错误:tid = 0x2203, 0x016ba09b libobjc.A.dylib`objc_msgSend + 15, stop reason = EXC_BAD_ACCESS (code=1, address=0x439a0008) 这绝对是发送的问题向不存在的对象发送消息,或者至少无法接收该特定消息。我的猜测是,图像正在通过某种仅限链接的方式进行更新。然后链接被破坏,程序崩溃。我不确定如何解决这个问题。有没有办法将图像永久分配给 UIImageView 使其独立?

标签: ios image image-processing


【解决方案1】:

我更改了我的 dispayImage() 方法以接收 UIImageView 属性并返回 VOID。这样,所有工作都对传递的 UIImageView 完成,而不是本地化实例,并且没有返回任何内容。

我的猜测是我之前使用的返回的 UIImage 方法崩溃了,因为返回的引用在方法完成的第二秒被释放。这也让我可以使用 CGImageRelease 而不会产生任何不良影响。

这是新方法:

- (void)displayImage:(UIImageView *)image
{
   CGContextRef context;
   CGImageRef imageRef = [image.image CGImage];

   CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
   context = CGBitmapContextCreate(rgbaDataNew, width, height, 8, 4 * width, colorSpace,  kCGImageAlphaPremultipliedLast ); 
   imageRef = CGBitmapContextCreateImage (context);
   image.image = [UIImage imageWithCGImage:imageRef];
   CGColorSpaceRelease(colorSpace);    
   CGContextRelease(context);  
   CGImageRelease(imageRef);
   image = nil;
}

感谢所有提供帮助的人!仅从您的建议中,我就学到了很多东西。这是我第一次使用 bt 和 NSZombie,现在我正在虔诚地使用它们!再次感谢!

【讨论】:

    【解决方案2】:

    您正在释放 imageRef,这会导致 UIImage 被自动释放。

    确保您保留 UIImage 以防止此类事件发生:

    - (UIImage *)displayImage
    {
        CGContextRef context;
    
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        context = CGBitmapContextCreate(rgbaDataNew, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast ); 
    
        CGImageRef imageRef = CGBitmapContextCreateImage (context);
        UIImage *outputImage = [[UIImage imageWithCGImage:imageRef] retain]; 
    
        CGColorSpaceRelease(colorSpace);    
        CGContextRelease(context);  
        CGImageRelease(imageRef); //this line would cause outputImage to be released
        return outputImage;
    }
    

    【讨论】:

    • 我尝试删除该行,但仍然得到相同的 [Not A Type retain] 错误。我什至尝试删除所有 3 条 CG..Release 行,但仍然出现相同的错误。
    • 您不需要删除那些发布行。上面的代码应该可以正常工作。
    • 很抱歉,我没有看到您添加的 retain 选项。我正在使用 ARC,不幸的是,不能使用 retain 命令。还有其他选择吗?我很抱歉没有注意到我之前使用的 Xcode 版本。感谢您的帮助。
    • 啊,好吧,在这种情况下,我认为您应该关闭该课程的 ARC,或者查看@Matthew Fredericks 的回答。
    【解决方案3】:

    displayImage 告诉编译器你想用__strong 保留图像:

    UIImage __strong *outputImage = [UIImage imageWithCGImage:imageRef];
    

    或者如果您愿意:

    __strong UIImage *outputImage = [UIImage imageWithCGImage:imageRef];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-04
      • 1970-01-01
      • 2017-03-09
      • 1970-01-01
      • 2019-11-09
      • 1970-01-01
      • 2016-03-12
      相关资源
      最近更新 更多