Observer in NSNotification (itemDidFinishPlaying) RANDOMLY to called twice
Asked Answered
S

3

6

I am displaying a text as soon as a video is done playing. I am using a notification technique to achieve that. The only problem is that the Observer is called twice every now and then. It triggers the "itemDidFinishPlaying" twice (and therefore the method of the same name). I cannot predict when. I don't know why. It looks random (I know this sounds weird) like it's working fine let's say 15 times in a row and the next time that behaviour happens out of the blue. I do a rebuild and run the app and this time it runs fine 19 times in a row before calling the Observer twice, etc... Unpredictable. I've tried every scenarios to predict the bug in order to fix it. It's been impossible so far. So I have 2 questions.

1) Why does it happen and "randomly"?

2) How to fix this double calling issue?

Also these 2 following conversations have not helped:

Why the Observer in NSNotification called twice....?

How to stop the Observer in NSNotification to called twice?

Please find my code below:

- (void) playAnimation: (NSString *) theString {

UIView *thisCurrentView = self.currentView;
UIView *thisReplacementView = [[UIView alloc] init];

//[avPlayer pause];
[self replaceView: thisCurrentView withView: thisReplacementView];

NSString *filepath = [[NSBundle mainBundle] pathForResource:theString ofType:@"mov"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];


 // First create an AVPlayerItem
 AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:fileURL];

 // Subscribe to the AVPlayerItem's DidPlayToEndTime notification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];

 // Pass the AVPlayerItem to a new player
 controlledPlayer = [[AVPlayer alloc] initWithPlayerItem:playerItem];


AVPlayerLayer *animatedLayer = [AVPlayerLayer playerLayerWithPlayer:controlledPlayer];


[animatedLayer setFrame:CGRectMake(0, 0, 1024, 1024)];
[thisReplacementView.layer addSublayer: animatedLayer];


// Begin playback
[controlledPlayer play];

// Clear some content
[self displayNoContent];

pageContent = theString;


playingStatus = YES;

}

-(void)itemDidFinishPlaying {

[self displayContent: pageContent];

}

Spoor answered 27/4, 2013 at 4:51 Comment(7)
Are you adding your notification observer in video play button action?Hyperthyroidism
@NSUserDefault, no button. I'm just swiping to navigate. The animation is played once the page is displayed.Spoor
where you are calling this - (void) playAnimation: (NSString *) theString method?Hyperthyroidism
In (IBAction)HandleSwipe:(UISwipeGestureRecognizer *)sender method that launch the animation after the user swipe to display next or previous page.Spoor
Have tried the answer I given?Hyperthyroidism
I will and let you know. But here's the thing: At this point the issue is randomly happening and in an unpredictable way. So even if that new line resolved it I won't have any proof it won't happen in the future. That's why I also need to know the WHY :-)Spoor
It's working so far with this adjustment [[NSNotificationCenter defaultCenter] removeObserver:self];Spoor
H
8

Try this,

-(void)itemDidFinishPlaying {

      [self displayContent: pageContent];
      [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];

}

It may work for you.

EDIT1:

Remove the notification observer every-time before you set the new one.Try the below scenario.It will ensure, remove the previous observer(even it doesn't exist no problem) and adds the new one.

// Subscribe to the AVPlayerItem's DidPlayToEndTime notification.

[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
Hyperthyroidism answered 27/4, 2013 at 5:5 Comment(3)
For now I'm resolving it with a conditional statement to only print the text once. So if the notification happen the second time in a row it only display the text one time. Not the sexiest approach around but for now it allows me to move forward.Spoor
It's working so far with this line... Thanks [[NSNotificationCenter defaultCenter] removeObserver:self];Spoor
The only reason for your problem should be, you are adding notification observer more than once. Please check your code once, even remove observer before adding every-time.So it ensures, you are not having the previous observer with same name.Please check my edited answer.Hyperthyroidism
A
1

This only happens to me during AirPlay. I'm using the following workaround to ignore the duplicate notification.

if ([notificaiton.object isEqual:self.player.currentItem] && (self.player.rate > 0))
{
    [self.player pause];

    //Do your stuff here.
}

NSUserDefault's answer also works but then you have to add the observers again and could be complicated depending on your setup.

Anjelicaanjou answered 22/7, 2015 at 13:20 Comment(0)
S
0

1) Verify you only have one observer, and not dangling ones from the view controller not deallocating as expecting.

2) If you verified there's only one observer, it sounds like you could use a tracking variable and ignore anything after the first instance of the notification. Not elegant, but it should work.

Storied answered 19/7, 2018 at 8:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.