Objective c 我在q1上的dispatch_async调用了主队列上的UI对象,它在q1上添加了回调,崩溃了

Objective c 我在q1上的dispatch_async调用了主队列上的UI对象,它在q1上添加了回调,崩溃了,objective-c,multithreading,objective-c-blocks,grand-central-dispatch,Objective C,Multithreading,Objective C Blocks,Grand Central Dispatch,听起来很混乱,但看起来是这样的 AVPlayer *capturedPlayer = _player; dispatch_async(_subtitlesQueue, ^{ // Parse the requested subtitle track and create a subtitle time observer subripString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringE

听起来很混乱,但看起来是这样的

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(或类似)的调用的子标题队列中

如果我将周期时间观察程序添加到主队列而不是自定义串行队列,则异步调用也可以工作。然而,文档说添加到不同的队列应该是可以的

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

干杯,谢谢你的帮助

编辑: 例外情况是EXC_BAD_访问代码2,因此不应该访问的内容是。它发生在运行_subtitlesque的单独线程上。它发生在对[AVPlayerPeriodicCaller\u effectiveRateChanged]的调用中

在调用addPeriodicTimeObserver之前,我还打印了CapturedLayer和_SubtitleQueue(指针值)的值,在调用_SubtitleQueue上的外部调度异步之前,在调用主队列上的内部调度异步之前,以及在调用addPeriodicTimeObserver上的调度异步内部。他们都一样

编辑2: 如果我在队列上的周期性时间观察者创建周围添加一个同步块,那么事情就正常了

@synchronized(_subtitlesQueue) {
    _subtitlesTimeObserver = [capturedPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 5)
                                                                          queue:_subtitlesQueue
                                                                     usingBlock:subtitleTimeObservedBlock];
}
当您向正在播放的AVPlayer添加定期观察者时,
-[AVPlayerPeriodicCaller\u effectiveRateChanged]
中似乎出现了所有内容。我正在使用的解决方法是:

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

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

if (playing)
{
    [player play];
}
正如您所指出的,另一种解决方法是传递
NULL
而不是串行队列,因为这会使块在主线程调度队列上排队。

当您向正在播放的AVPlayer添加定期观察者时,
-[AVPlayerPeriodicCaller\u effectiviverateChanged]
。我正在使用的解决方法是:

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

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

if (playing)
{
    [player play];
}

正如您所指出的,另一种解决方法是传递
NULL
而不是串行队列,因为这会使主线程调度队列上的块排队。

subtitlesQueue是局部变量吗?实例变量?它是什么时候创建和发布的?\u subtitlesque是在初始化视图控制器时创建的成员变量。哦,它的发布应该由ARC处理(从ios6开始)。您能否提供一个显示问题的小型但自包含的示例程序?
\u subtitlesque
是局部变量吗?实例变量?它是何时创建和发布的?\u subtitlesQueue是在初始化视图控制器时创建的成员变量。哦,它的发布应该由ARC处理(从ios6开始)。您能否提供一个小型但自包含的示例程序来显示问题?感谢erikprice,这已经是一个很长的时间了。从那时起,代码已经改变了很多,所以我不能确认,但是很高兴知道:)谢谢erikprice,这已经是很长一段时间了。从那以后,代码发生了很大的变化,所以我无法确认,但很高兴知道:)