【问题标题】:UIImage within Thread not being Released / Overwritten线程内的 UIImage 未被释放/覆盖
【发布时间】:2009-11-03 13:20:02
【问题描述】:

这似乎是从 iPhone 扫描图像的经典方法。我有一个从主线程调度的线程去扫描代码。它基本上每次都会创建一个新的 UIImage,然后将其删除。

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    { 
        while (![thread isCancelled]) {
#ifdef DEBUG
            NSLog(@"Decoding Loop");
#endif
        //  [self performSelectorOnMainThread:@selector(updateImageBuffer) withObject:nil waitUntilDone:YES];           
            CGImageRef cgScreen = UIGetScreenImage();
            UIImage *uiimage = [UIImage imageWithCGImage:cgScreen];

            if (uiimage){
                CGSize size = [uiimage size];
                CGRect cropRect = CGRectMake(0.0, 80.0, size.width, 360); // Crop to centre of the screen - makes it more robust
#ifdef DEBUG
                NSLog(@"picked image size = (%f, %f)", size.width, size.height);
#endif
                [decoder decodeImage:uiimage cropRect:cropRect];
            }
            [uiimage release];
            CGImageRelease(cgScreen);
        }
    }
    [pool release];

问题在于 [pool release] 会导致 ERROR_BAD_EXC(旧经典)和程序炸弹。有人告诉我没有必要调用 [uiimage release],因为我没有明确分配 UIImage,但情况似乎并非如此。如果我去掉那条线,内存使用量就会飙升,程序会因为内存不足而退出。看来我无法按照我想要的方式完成这项工作。

有没有办法“就地”创建 UIImage?即,有一个作为 UIImage 一次又一次写入的缓冲区?我怀疑这会起作用吗?

更新!

尝试在主线程执行UIKit相关调用如下:

-(void)performDecode:(id)arg{

    // Perform the decoding in a seperate thread. This should, in theory, bounce back with a 
    // decoded or not decoded message. We can quit at the end of this thread.
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    { 
        while (![thread isCancelled]) {

#ifdef DEBUG
            NSLog(@"Decoding Loop");
#endif
            [self performSelectorOnMainThread:@selector(updateImageBuffer) withObject:nil waitUntilDone:YES];           

            if (uiimage){
                CGSize size = [uiimage size];
                CGRect cropRect = CGRectMake(0.0, 80.0, 320, 360); // Crop to centre of the screen - makes it more robust
#ifdef DEBUG
                NSLog(@"picked image size = (%f, %f)", size.width, size.height);
#endif
                [decoder decodeImage:uiimage cropRect:cropRect];
            }
        }
    }
    [pool drain];


#ifdef DEBUG
    NSLog(@"finished decoding.");
#endif


}

-(void) updateImageBuffer {
    CGImageRef cgScreen = UIGetScreenImage();
    uiimage = [UIImage imageWithCGImage:cgScreen];
    //[uiimage release];
    CGImageRelease(cgScreen);
}

当人们想要获取 UIImage 的“大小”时,EXC_BAD_ACCESS 抬起了丑陋的脑袋,这并不令人高兴

【问题讨论】:

    标签: iphone multithreading uiimage cgimage


    【解决方案1】:

    正如其他人所说,您不应该释放从 imageWithCGImage: 返回的 UIImage。它是自动发布的。当您的池耗尽时,它会尝试向您已发布的图像对象发送一条发布消息,从而导致您的崩溃。

    您的内存使用量不断攀升的原因是您只在循环之外耗尽了自动释放池。您的自动释放对象不断在循环内累积。 (顺便说一句,您需要在该方法结束时释放您的自动释放池,因为它当前正在泄漏。)为了防止这种积累,您可以在循环中定期排空池。

    但是,我建议切换到执行[[UIImage alloc] initWithCGImage:cgScreen],然后在完成后发布图像。我尽量避免在 iPhone 应用程序中使用自动释放的对象,以便更严格地控​​制内存使用和整体更好的性能。

    【讨论】:

    • 干杯!我在之前的评论中提到了这一点,但感谢 Drain 的提示。关键是要弄清楚便利方法坚持使用自动释放,因此提前释放是行不通的。
    【解决方案2】:

    UIGetScreenImage() 是私有且未记录的,因此您完全无法使用它。说什么都没有表明你现在拥有 CGImageRef cgScreen 那么你为什么要发布它呢?您也无法知道它是否是线程安全的,因此应该假设它不是。然后你继续释放你没有初始化、保留或复制的 IImage *uiimage,所以再次 - 你不拥有它。查看docs

    【讨论】:

    • 私人或非私人在这一点上与我无关。 cgScreen 上的 release 方法取自另一段代码。我已经查看了文档并且我同意不应该发布 uiimage 但是正如我所说的,如果这条线没有到位,内存只会不断攀升
    【解决方案3】:

    [uiimage release] 在这种情况下肯定是错误的。此外,Apple 强调所有 UIKit 方法都必须在主线程上执行。这包括UIGetScreenImage()+[UIImage imageWithCGImage:]

    编辑:所以在错误的线程上调用-[UIImage size] 时会出现异常。这可能不应该让您感到惊讶,因为这是不允许的。

    【讨论】:

    • 是的,我就是这么想的。我把它删掉了,但我正在使用的内部库也在对 UIImage 做这样的事情,所以......对那个不满意。
    【解决方案4】:
    UIImage *uiimage = [[UIImage alloc] initWithCGImage: cgScreen];
    

    明确说明我最清楚何时释放该对象似乎有效。虚拟内存仍在增加,但物理内存现在保持不变。感谢您指出 UIKit 线程安全问题。这是我错过的一点,但目前似乎不影响跑步。

    另外,我应该指出,Red Laser 和 Quickmark 都使用这种扫描相机信息的方法;)

    【讨论】:

      猜你喜欢
      • 2014-06-27
      • 2018-06-21
      • 2013-05-24
      • 1970-01-01
      • 1970-01-01
      • 2019-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多