听起来令人困惑,但看起来像这样
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的新手和整个队列的事情,所以也许我很误解,但不应该上面的工作吗?
如果我将主队列上的呼叫更改为同步,那么它可以正常工作。在调用AVPlayer的makePeriodicCall(或类似内容)时,来自subtitleQueue的崩溃。
如果我将定期时间观察器添加到主队列而不是自定义串行队列,则异步调用也可以。但是,文档说添加不同的队列应该没问题。
问题2) 虽然我在这里,但我也有一个关于“捕获”AVPlayer的部分的问题。是否足够安全地捕获变量,还是必须使用__weak并确保它在块内不是NULL?我的情况是包含AVPlayer的控制器是单例,因此它在应用程序的整个生命周期中都存在。我认为这不会使用__weak修饰符。我是否正确地想到这一点?
干杯,谢谢你的帮助!
编辑: 例外是EXC_BAD_ACCESS代码2,因此不应访问的内容是。它发生在运行_subtitlesQueue的单独线程上。它发生在调用[AVPlayerPeriodicCaller _effectiveRateChanged]
我还在_subtitlesQueue上调用外部dispatch_async之前打印出了capturePlayer和_subtitlesQueue(指针值)的值,然后在主队列上调用内部dispatch_async之前,在addPeriodicTimeObserver之前调用主队列上的dispatch_async之前调用。他们都是一样的。
EDIT2: 如果我在subtitleQueue上创建周期性时间观察者周围添加一个同步块,那么事情就可以了......
@synchronized(_subtitlesQueue) {
_subtitlesTimeObserver = [capturedPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 5)
queue:_subtitlesQueue
usingBlock:subtitleTimeObservedBlock];
}
全部
答案 0 :(得分:1)
当您向播放AVPlayer添加定期观察者时,-[AVPlayerPeriodicCaller _effectiveRateChanged]
中似乎有a bug that causes EXC_BAD_ACCESS。我正在使用的解决方法是:
BOOL playing = player.rate > 0.0f;
if (playing)
{
[player pause];
}
[player addPeriodicTimeObserverForTimeInterval:myTime queue:mySerialQueue usingBlock:myBlock];
if (playing)
{
[player play];
}
正如您所指出的,另一种解决方法是传递NULL
而不是串行队列,因为这会使主要线程调度队列上的块入队。