【问题标题】:NSRunLoop and GCD queuesNSRunLoop 和 GCD 队列
【发布时间】:2011-03-02 00:21:30
【问题描述】:

我正在创建一个用于 iOS 的 c++ 库(是的,不幸的是它必须是 C++),它使用 AVCaptureSession 来捕获通过 captureOutput 回调传递的视频帧。 C++ 库是我可交付的产品。我有一个可可触摸应用程序来测试/演示它。所以,它看起来像这样:

(测试应用程序)(c++ lib(AVFoundation回调))

测试应用具有 UI 控件并负责几乎所有图形。 c++ 库通过 OpenGL 将帧渲染到 UIView。

你和我在一起吗?不错


好的,首先,用户按下一个 UIButton 来调用我的库。此调用需要 10 秒或更长时间才能完成。所以如果我把调用直接放在按钮点击后面,UI会一直阻塞,直到库函数返回:

-(IBAction)hBut:(id)sender{
    [myLib foo]; // takes 10+ seconds to return
}

这不好。我尝试的下一件事是生成一个线程来调用 lib:

-(void)callIntoLib{
    [myLib foo];
}

-(IBAction)hBut:(id)sender{
    [NSThread detach..:myLib selector:foo object:nil];
}

这不再阻塞 UI,但现在视频帧回调函数永远不会触发(AVCaptureSession 的 captureOutput)。似乎主 NSRunLoop 已被阻止。

接下来我尝试了同样的事情,但使用的是 Grand Central Dispatch:

-(IBAction)hBut:(id)sender{
     _myQueue = dispatch_queue_create("com.domain.me", NULL); // member variable
     dispatch_async(_myQueue,
     ^{
          [myLib foo];
     });
}

这具有相同的行为。也就是说,视频帧的回调不会触发。跛脚

为什么主 NSRunLoop 在第 2 和第 3 种情况下被阻塞?有没有办法将队列与之关联?

这有意义吗?

【问题讨论】:

    标签: iphone ios grand-central-dispatch nsrunloop avcapturesession


    【解决方案1】:

    主线程自己运行它的 runLoop,因此在第一种情况下,来自相机的事件被传递到您的库。自定义线程不运行runLoop,你应该自己做。

    -(void)callIntoLib {
        [myLib foo];
        self.callIntoLibExecuted = YES;
    }
    
    
    -(void)threadBody {
        @autoreleasepool {
            self.callIntoLibExecuted = NO;
    
            [self performSelector:@selector(callIntoLib) 
                     onThread:[NSThread currentThread] 
                     withObject:nil
                     waitUntilDone:NO];
    
            while (!self.callIntoLibExecuted)
            {
               @autoreleasepool {
                   [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                             beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
               }
            }
        }
    }
    
    -(IBAction)hBut:(id)sender {
        [NSThread detachNewThreadSelector:@selector(threadBody) 
                  toTarget:self withObject:nil];
    }
    

    【讨论】:

    • 你试过了吗?我有一个自定义的 thread with its own runloop 并且仍然 AVFoundation 来自主运行循环。如果主运行循环被阻塞,它就不会出现(我说的是 OSX 而不是 iOS)。
    • 我认为 AVFoundation 在 OSX 上的工作方式与 iOS 不同,这个答案是为 iOS 问题提供的。如果您将使用 AVCaptureVideoDataOutput 而不是 AVCaptureMovieFileOutput,您将能够在您指定的调度队列中捕获回调。试试看。也许那时你的主线程在捕获期间不会被使用。
    【解决方案2】:

    此示例代码仅在 GCD 串行队列上使用 AVCaptureVideoDataOutput -setSampleBufferDelegate:queue:。看来 AVCaptureSession 必须和 RunLoop 一起使用。你需要在你的线程上执行你自己的 RunLoop,或者尝试修改你的 C++ 库作为这个示例代码。

    【讨论】:

    • 那个 li k 现在被破坏了(Apple 的邪恶网站管理员不断破坏 url)。新版本在:developer.apple.com/library/ios/qa/qa1702/_index.html
    • 看来即使线程有自己的runloop,AVCaptureSession 也坚持要在主runloop (CFRunLoopGetMain) 上运行。我spawn NSThread 并在其中运行所有内容,但回调仅来自主运行循环,如果主运行循环阻塞,则不会收到回调。如果我在主循环上做所有事情都很好,只是它不喜欢新线程。我说的是 OSX 而不是 iOS。
    猜你喜欢
    • 1970-01-01
    • 2012-09-26
    • 1970-01-01
    • 2012-03-25
    • 2013-10-11
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 2012-12-17
    相关资源
    最近更新 更多