这似乎是从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会变得难看
答案 0 :(得分:1)
UIGetScreenImage()是私有的,没有文档,因此你不能使用它。说它没有任何关于它表明你现在拥有CGImageRef cgScreen所以你为什么要发布它?你也无法知道它是否是线程安全的,所以应该假设它不是。然后你继续发布你没有初始化,保留或复制的IImage * uiimage,所以再次 - 你不拥有它。查看docs。
答案 1 :(得分:1)
正如其他人所说,你不应该释放从imageWithCGImage返回的UIImage :.它是自动释放的。当您的游泳池耗尽时,它会尝试向您已发布的图像对象发送一条释放消息,从而导致您的崩溃。
你的内存使用不断攀升的原因是你只是在循环之外排出自动释放池。您的自动释放对象会在循环内部累积。 (顺便说一下,你需要在该方法结束时释放自动释放池,因为它当前正在泄漏。)为了防止这种累积,你可以在循环内定期排空池。
但是,我建议切换到执行[[UIImage alloc] initWithCGImage:cgScreen]
,然后在完成后释放图像。我尽量避免在iPhone应用程序中使用自动释放的对象,以便更严格地控制内存使用情况和整体更好的性能。
答案 2 :(得分:0)
[uiimage release]
绝对是错误的。此外,Apple强调必须在主线程上执行所有UIKit方法。其中包括UIGetScreenImage()
和+[UIImage imageWithCGImage:]
。
编辑:因此,在错误的线程上调用-[UIImage size]
时会出现异常。这可能不会让你感到惊讶,因为它是不允许的。
答案 3 :(得分:0)
UIImage *uiimage = [[UIImage alloc] initWithCGImage: cgScreen];
明确说明我知道何时发布该对象似乎最有效。虚拟内存仍在增加,但物理现在保持不变。感谢您指出UIKit线程安全问题。这是我错过的一点,但似乎不会影响此时的跑步。
另外,我应该指出,Red Laser和Quickmark都使用这种扫描相机信息的方法;)