iOS自动线程?

时间:2012-06-25 17:15:56

标签: objective-c ios multithreading

我一直致力于iOS的opencv项目。我得到了一个简单的项目,开始使用捕获和显示的帧进行开发。在我开始遇到内存问题并将其追溯到原始项目设置之前,我从未关注它是如何工作的。我现在计划重新编写捕获/显示代码,但我不明白为什么它首先起作用。有一个播放/暂停按钮,调用方法

- (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];
    }
  }
}

play只是一个全球性的bool,表示应用程序是在播放还是暂停。奇怪的是,处理应该在一个无限循环内发生,没有出路。在循环中永远不会修改播放。尽管如此,当应用程序运行时,播放/暂停按钮仍然保持响应并且能够翻转播放bool并暂停执行。不仅如此,其他bool(例如use_greyscale)可以被其他按钮翻转,并且它们的值在循环内部发生变化。我原本期望应用程序冻结,甚至不会在屏幕上绘制新帧。应用程序应该在其生命周期的大部分时间内被困在该函数内,无法执行其他任务,例如绘图和UIControl。似乎唯一可行的方法是IBAction调用是否在自己的线程上运行。我在源代码中找不到任何线程的证据。有人可以解释苹果如何在其UI中处理线程?我的印象是有一个主要的runloop线程,并且没有自动创建额外的线程。如果这是真的,那么如何解释这种行为呢?

旁注 -

最终让我调查的是[UIImage imageWithCVMat:_display_frame]返回一个自动释放的对象。由于所有这些都发生在循环中,因此如果没有暂停执行导致崩溃,则无法释放对象。

2 个答案:

答案 0 :(得分:3)

原因之所以有效,是因为cv::VideoCapture::grab()方法的实现运行当前的运行循环来暂停线程直到它获得一个帧。

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

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

如果在触摸按钮暂停时查看callstack,您会看到:

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

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

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

答案 1 :(得分:0)

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

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