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];

}

Community
  • 1
  • 1
Armand
  • 435
  • 1
  • 11
  • 23
  • Are you adding your notification observer in video play button action? – NSUserDefault Apr 27 '13 at 04:55
  • @NSUserDefault, no button. I'm just swiping to navigate. The animation is played once the page is displayed. – Armand Apr 27 '13 at 04:58
  • where you are calling this - (void) playAnimation: (NSString *) theString method? – NSUserDefault Apr 27 '13 at 05:05
  • In (IBAction)HandleSwipe:(UISwipeGestureRecognizer *)sender method that launch the animation after the user swipe to display next or previous page. – Armand Apr 27 '13 at 11:12
  • Have tried the answer I given? – NSUserDefault Apr 27 '13 at 11:15
  • 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 :-) – Armand Apr 27 '13 at 12:50
  • 1
    It's working so far with this adjustment [[NSNotificationCenter defaultCenter] removeObserver:self]; – Armand May 05 '13 at 23:14

3 Answers3

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];
NSUserDefault
  • 1,794
  • 1
  • 17
  • 38
  • 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. – Armand May 05 '13 at 20:31
  • It's working so far with this line... Thanks [[NSNotificationCenter defaultCenter] removeObserver:self]; – Armand May 05 '13 at 23:14
  • 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. – NSUserDefault May 06 '13 at 10:44
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.

flopr
  • 450
  • 4
  • 23
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.

Crashalot
  • 33,605
  • 61
  • 269
  • 439