问题
I'm using AVPlayer's -addBoundaryTimeOserverForTimes:queue:usingBlock: to execute some code at a specific time in my video (in this case, I want a un-hide a button when my video reaches its duration. Code is as follows:
- (void)viewWillAppear:(BOOL)animated
{
...
_player = [AVPlayer playerWithURL:videoURL];
AVPlayerLayer *newPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
[newPlayerLayer setFrame:_videoView.bounds];
[_videoView.layer addSublayer:newPlayerLayer];
_observer = [_player addBoundaryTimeObserverForTimes:@[[NSValue valueWithCMTime:_player.currentItem.duration]] queue:NULL usingBlock:^{
[someButton setHidden:NO];
}];
...
}
For whatever reason, sometimes the block of code fires and the button becomes visible, and sometimes it doesn't. Haven't been able to find a pattern in this behavior. It happens very often (almost always) in the simulator, and occasionally when on a device. Has anyone encountered this problem? Any ideas what might be going on?
Edit
Also, if I put a breakpoint on the block, it ALWAYS fires.
回答1:
Main queue sometimes not call. You can use Sub queue, and call Main queue in Sub-queue's block.
// dispatch queue setting
dispatch_queue_t subQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
// notification setting
__block id blockObserver;
blockObserver = [self.queuePlayer addBoundaryTimeObserverForTimes:boundary
queue:subQueue // if NULL use mainQueue
usingBlock:^{
// do something
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
// do something
});
}];
回答2:
For those wanting to observe when the player ends:
I browse this question about once a year because I always forget about the fix that works for me. This time around I had this issue on macOS. I am seeing the same behavior, the observer block sometimes does not get called. When I switch back from the app that is being debugged to Xcode the block suddenly fires. This might be related to having a breakpoint set in the block as described by the OP.
Here's the fix however: Simply switch to AVPlayerItemDidPlayToEndTimeNotification
as described in this answer. Note however, as the name implies the notification's object is the player's current item not the player itself!
Because this notification triggers at the end time of an item, instead of observing some "boundary time" simply set the item's forwardPlaybackEndTime
if you need another time than the item's actual end time, i.e. duration.
来源:https://stackoverflow.com/questions/15771549/avplayer-boundary-time-observer-fails-to-fire-occasionally