0

这似乎是从 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 抬起了丑陋的脑袋,这并不令人高兴

4

4 回答 4

1

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

于 2009-11-03T13:46:22.737 回答
1

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

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

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

于 2009-11-03T18:38:51.233 回答
0

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

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

于 2009-11-03T13:39:58.543 回答
0
UIImage *uiimage = [[UIImage alloc] initWithCGImage: cgScreen];

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

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

于 2009-11-03T14:41:47.070 回答