1

听起来令人困惑,但看起来像这样

AVPlayer *capturedPlayer = _player;
dispatch_async(_subtitlesQueue, ^{
    // Parse the requested subtitle track and create a subtitle time observer
    subripString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    subripEntries = [SubRipParser parse:subripString];
    if (!subripEntries.count)
        return;
    dispatch_async(dispatch_get_main_queue(), ^{
        _subtitlesTimeObserver = [capturedPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 5)
                                                                              queue:_subtitlesQueue
                                                                         usingBlock:^(CMTime time){}];
    });
});

单击按钮时会调用上面的代码。它崩溃了。我是 GCD 和整个队列的新手,所以也许我误解了,但上述工作不应该吗?

如果我将主队列上的调用更改为同步调用,那么它可以工作。崩溃发生在 subtitleQueue 调用 AVPlayer 的 makePeriodicCall (或类似)时。

如果我将周期性时间观察器添加到主队列而不是自定义串行队列,则异步调用也有效。但是,文档说添加到不同的队列应该没问题。

问题2)当我在这里时,我还有一个关于“捕获” AVPlayer 的部分的问题。捕获这样的变量是否足够安全,或者我是否必须使用 __weak 并确保它在块内不为 NULL?我的情况是包含 AVPlayer 的控制器是单例的,因此它存在于应用程序的整个生命周期中。我认为这使得不使用 __weak 修饰符可以。我这样想对吗?

干杯,感谢您的帮助!

编辑:例外是 EXC_BAD_ACCESS 代码 2,所以不应该访问的是。它发生在运行 _subtitlesQueue 的单独线程上。它发生在调用 [AVPlayerPeriodicCaller _effectiveRateChanged]

在 _subtitlesQueue 上调用外部 dispatch_async 之前、在主队列上调用内部 dispatch_async 之前以及在调用 addPeriodicTimeObserver 之前在主队列上的 dispatch_async 内部之前,我还打印了 capturePlayer 和 _subtitlesQueue 的值(指针值)。他们都是一样的。

EDIT2:如果我在 subtitleQueue 上的周期性时间观察者创建周围添加一个同步块,那么一切正常......

@synchronized(_subtitlesQueue) {
    _subtitlesTimeObserver = [capturedPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 5)
                                                                          queue:_subtitlesQueue
                                                                     usingBlock:subtitleTimeObservedBlock];
}

全部

4

1 回答 1

1

当您将周期性观察者添加到正在播放的 AVPlayer 时,似乎存在导致 EXC_BAD_ACCESS 的错误-[AVPlayerPeriodicCaller _effectiveRateChanged]我正在使用的解决方法是:

BOOL playing = player.rate > 0.0f;
if (playing)
{
    [player pause];
}

[player addPeriodicTimeObserverForTimeInterval:myTime queue:mySerialQueue usingBlock:myBlock];

if (playing)
{
    [player play];
}

正如您所指出的,另一种解决方法是通过NULL而不是串行队列,因为这具有将主线程调度队列中的块排队的效果。

于 2013-08-29T15:50:58.130 回答