2012-06-25 24 views
2

我一直在为iOS开发一个opencv项目。我得到了一个简单的项目,开始使用捕获和显示的帧进行开发。在我开始记忆问题并追溯到原始项目设置之前,我从未注意过它是如何工作的。我现在打算重新编写捕获/显示代码,但我不明白它为什么起作用。有一个播放/暂停按钮,它调用的方法iOS自动穿线?

- (IBAction)play_pause:(id)sender 
{ 
    play = !play; 
    while(play) 
    { 
    if (_videoCapture && _videoCapture->grab()) 
    { 
     (*_videoCapture) >> _display_frame; 
     //process frame 
     self.imageView.image = [UIImage imageWithCVMat:_display_frame]; 
    } 
    } 
} 

该剧只是表示该应用程序是否正在播放或暂停一个全球性的布尔。奇怪的是,处理应该在无限循环内进行,没有出路。在循环内从不修改播放。尽管如此,当应用程序运行时,播放/暂停按钮保持响应,并且能够翻转播放布尔并暂停执行。不仅如此,其他布尔(例如use_greyscale)可以被其他按钮翻转,并且它们的值在循环内部改变。我本来希望应用程序冻结,甚至从未画出新的画面。应用程序应该一直处于该函数的大部分生命周期内,无法执行其他任务,如绘图和UIControl。看起来好像这是可能的唯一方法是如果IBAction调用运行在它自己的线程上。我在源代码中找不到任何线程的证据。有人能解释一下苹果如何在UI中处理线程吗?我的印象是有一个主循环线程,并且没有自动创建多余的线程。如果那是真的,这个行为怎么解释呢?

侧笔记记录

什么终于让我调查这是[UIImage的imageWithCVMat:_display_frame]返回一个自动释放的对象。由于所有这些都发生在一个循环中,所以如果没有导致崩溃的执行被暂停,对象就不能被释放。

回答

3

原因是工作是因为执行cv::VideoCapture::grab()方法运行当前运行循环暂停线程,直到它获得一个框架。

当您启动应用程序时,main函数执行名为UIApplicationMain的函数,该函数执行CFRunLoopRun。当在主线程上执行CFRunLoopRun时,它运行主运行循环,该循环是处理从系统接收到的所有UI事件并刷新用户界面的运行循环。有关运行循环的信息,您可以阅读Apple Threading Programming Guide

所以,当你执行一个无限循环时,你的代码永远不会返回到运行循环,并且等待事件不能被处理。但在你的情况下,grab方法再次运行运行循环,并具有到期延迟。因此,运行循环可能会处理传入的事件(可能会再次调用您的代码),直到延迟到期,然后返回到您的代码,再次运行循环。

如果你看看调用堆栈当你触摸按钮暂停,你会看到:

主要功能→运行循环→事件处理→代码→OpenCV的→运行环→事件处理→代码

运行循环在其内部运行,这很好,因为运行循环是可重入的。滚动视图实际上使用该行为:滚动UIScrollView时,它会以不同的模式再次运行循环,以便在结束滚动之前忽略某些事件。

但我不确定OpenCV的开发人员在编写他们的代码时是否考虑到了这一点。所以我认为在后台线程/队列中加载帧会更好。

0

你是对的,iOS中没有“自动线程”。 Grand Central Dispatch(GCD)确实使线程更容易,但不会自动发生。

你可以在while循环中写一些调试代码并测试[NSThread isMainThread],看看play_pause是否确实在主UI线程上运行,我怀疑它不是。

+0

我用你的测试,它说主线程运行整个时间。我还将该测试放在由其他按钮触发的函数调用中,以更改变量和布尔值,所有这些都在play/pause无限循环内更新了其值。我找不到[NSThread isMainThread]评估为NO的地方 – Hammer