NSNotificationCenter removing wrong observers? - ios

Is there any corner case behaviors for removeObserver:name:object:? In the following block of code, my observer isn't being registered properly:
- (void)setPlayerItem:(AVPlayerItem *)playerItem {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:nil
object:playerItem];
[playerItem addObserver:self
forKeyPath:kStatus
options:0
context:(__bridge void*)self];
[playerItem addObserver:self
forKeyPath:kPlaybackBufferEmpty
options:0
context:(__bridge void*)self]; // For adding a buffering activity indicator
id temp = playerItem_;
playerItem_ = [playerItem retain];
[[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:temp];
[temp removeObserver:self forKeyPath:kPlaybackBufferEmpty];
[temp removeObserver:self forKeyPath:kStatus];
[temp release];
}
However, if I change the order around to:
- (void)setPlayerItem:(AVPlayerItem *)playerItem {
[playerItem addObserver:self
forKeyPath:kStatus
options:0
context:(__bridge void*)self];
[playerItem addObserver:self
forKeyPath:kPlaybackBufferEmpty
options:0
context:(__bridge void*)self]; // For adding a buffering activity indicator
id temp = playerItem_;
playerItem_ = [playerItem retain];
[[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:temp];
[temp removeObserver:self forKeyPath:kPlaybackBufferEmpty];
[temp removeObserver:self forKeyPath:kStatus];
[temp release];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:nil
object:playerItem];
}
All the notifications post just fine. This leads me to believe something strange is happening when I call:
[[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:temp];
Am I missing something really obvious here? I'm on iOS 6 with no ARC.

Found the answer. Turns out it has to do with passing in nil for the observer name.
Calling [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:temp];
will remove self from observing any notifications posted by temp.
However, in the corner case that temp is nil, this line of code will remove self as an observer all together.

Name shouldn't be nil. Did you try giving your observer a name?

#Lee is correct that the name should not be nil but it also should not be the name of the observer. Rather it should be the name of the notification that you are registering to observe. e.g., UIDeviceOrientationDidChangeNotification.
Add the name of the notification that you want to observe in that param and also pass it as the name param when you remove observer

Related

In objective-c how to play multiple video url one after another with out inbetween buffering

In my project I have to play multiple video one after another from server and I have done the following code. My video is playing well but the problem is that while one video is finished I am playing the next video in the -(void)aMoviePlaybackComplete method a black screen is appearing for 1 or 2 seconds. I dont want that and also want to play the video without buffering. Is there any better way to do this? If possible please kindly share valuable code or related links.
Thanks in advance.
-(void)viewDidAppear:(BOOL)animated
{
NSURL * myUrl = [NSURL URLWithString:[arrVideoLink objectAtIndex:0]];
moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:myUrl];
moviePlayer.controlStyle=MPMovieControlStyleNone;
[vwVideoview addSubview:moviePlayer.view];
moviePlayer.view.frame = CGRectMake(0, 0, vwVideoview.frame.size.width, vwVideoview.frame.size.height);
moviePlayer.view.layer.zPosition = 1;
[moviePlayer prepareToPlay];
[moviePlayer play];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(aMoviePlaybackComplete:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(loadStateChanged:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(nowPlayingMovie:)
name:MPMoviePlayerNowPlayingMovieDidChangeNotification
object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doneButtonClick:)
name:MPMoviePlayerWillExitFullscreenNotification
object:moviePlayer];
}
- (void)aMoviePlaybackComplete:(NSNotification*)notification
{
if (urlIndex+1<=arrVideoLink.count-1)
{
NSURL * myUrl = [NSURL URLWithString:[arrVideoLink objectAtIndex:urlIndex+1]];
moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:myUrl];
moviePlayer.controlStyle = MPMovieControlStyleNone;
[vwVideoview addSubview:moviePlayer.view];
moviePlayer.view.frame = CGRectMake(0, 0, vwVideoview.frame.size.width, vwVideoview.frame.size.height);
moviePlayer.view.layer.zPosition = 1;
[moviePlayer prepareToPlay];
[moviePlayer play];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(aMoviePlaybackComplete:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(loadStateChanged:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:moviePlayer];
urlIndex++;
}
}else
{
[[NSNotificationCenter defaultCenter]removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
[[NSNotificationCenter defaultCenter]removeObserver:self name:MPMoviePlayerPlaybackStateDidChangeNotification object:moviePlayer];
[player.view removeFromSuperview];
}
}

NSMetadataQueryDidUpdateNotification, can't get this to work. Code Snippet included

I can't get the NSMetadataQueryDidUpdateNotification to work. Been stuck at it for days. Is there something abnormal in the code below.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0ul), ^{
NSString* filePattern = [NSString stringWithFormat:#"*.%#", #"*"];
NSMetadataQuery *aQuery = [[NSMetadataQuery alloc] init];
aQuery.predicate = [NSPredicate predicateWithFormat: #"%K LIKE %#", NSMetadataItemFSNameKey, filePattern];
[aQuery setSearchScopes:#[NSMetadataQueryUbiquitousDataScope]];
[aQuery setValueListAttributes:#[NSMetadataUbiquitousItemPercentDownloadedKey, NSURLUbiquitousItemDownloadingStatusKey,NSURLUbiquitousItemIsDownloadingKey,NSURLUbiquitousItemDownloadRequestedKey]];
_query = aQuery;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(liveUpdate:)
name:NSMetadataQueryDidUpdateNotification
object:aQuery];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(initalGatherComplete:) name:NSMetadataQueryDidFinishGatheringNotification object:aQuery];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(gatherProgress:) name:NSMetadataQueryGatheringProgressNotification object:aQuery];
[aQuery enableUpdates];
dispatch_async(dispatch_get_main_queue(), ^{
[aQuery startQuery];
});
});
Hope this helps you
Try replace with this code about notification
And metadata query should be started on main queue, you did it right :)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(liveUpdate:)
name:NSMetadataQueryDidUpdateNotification
object:aQuery];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(initalGatherComplete:)
name:NSMetadataQueryDidFinishGatheringNotification
object:aQuery];
And this is example for processing gathering notification
- (void)initialGatherComplete:(NSNotification*)notification
{
//process here.
}
The solution is to strong reference the notification block as such
_notifqueryDidUpdate = [[NSNotificationCenter defaultCenter]addObserverForName:NSMetadataQueryDidUpdateNotification object:aQuery queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
[self liveUpdate:note];
}];

NSNotification Not Received from Modal ViewController

What am I missing here? I'm just trying to send a simple notification from a modal view controller back to the view controller that launched it, but nothing gets received.
This is the code in the view controller that launches the modal segue:
- (IBAction) chooseSuperGroup:(UIButton *)sender {
NSLog(#"super group choice about to be made");
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(choiceReceived:)
name:#"selectionMade"
object:self];
}
- (void) choiceReceived: (NSNotification *) notification
{
NSLog(#"here");
if ([[notification name] isEqualToString:#"selectionMade"]) {
NSLog(#"received");
NSLog(#"%#", (NSString *)[notification userInfo]);
}
[[NSNotificationCenter defaultCenter] removeObserver:self
name: #"selectionMade"
object:self];
}
Then, over in the modal view controller, this code executes when the user selects a cell from the table view:
NSDictionary *dict = [NSDictionary dictionaryWithObject:selection forKey:#"superGroup"];
NSLog(#"printing dictionary contents");
for (id key in dict) {
NSLog(#"key: %# object: %#", key, [dict objectForKey:key]);
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"selectionMade" object:self userInfo:dict];
My output looks like this:
Super group choice about to be made
printing dictionary contents
key: superGroup object: myChoice
So the choice is captured and added to a dictionary. But there is no evidence of any notification being received. This can't be that hard, but I'm not seeing my mistake. Can someone help me? Thanks!
Try using 'nil' instead of 'self'
// Add Observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(choiceReceived:) name:#"selectionMade" object:nil];
// Remove Observer
[[NSNotificationCenter defaultCenter] removeObserver:self
name: #"selectionMade"
object:nil];
// Post Notification
[[NSNotificationCenter defaultCenter] postNotificationName:#"selectionMade" object:nil userInfo:dict];
refer:https://stackoverflow.com/a/8188759/2449268

iOS - Detect movie is finished

I am using MPMoviePlayerViewController to play a movie , I create a method which should detects when movie is finished then run a method :
- (void)movieFinishedWithSelector:(SEL)selectors {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(selectors)
name:MPMoviePlayerPlaybackDidFinishNotification
object:[player moviePlayer]];
}
and use this method like this , but does not work .
[self movieFinishedWithSelector:#selector(finished)];
Am I missing something ?
The selectors parameter is already a selector. Don't use #selector:
- (void)movieFinishedWithSelector:(SEL)selector {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:selector
name:MPMoviePlayerPlaybackDidFinishNotification
object:[player moviePlayer]];
}
create a notication when you load the movie
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(myMovieFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:movieController];
When finished the myMovieFinished will be called
-(void)myMovieFinished:(NSNotification *)aNotification
{
NSLog(#"%#",aNotification.userInfo);
int reason = [[[aNotification userInfo]valueForKey:MPMoviePlayerPlaybackDidFinishNotification]intValue];
if (reason==MPMovieFinishReasonPlaybackEnded) {
NSLog(#"Movie finished playing");
}
else if (reason==MPMovieFinishReasonUserExited)
{
NSLog(#"Movie finished because user exited");
}
else if (reason==MPMovieFinishReasonPlaybackError)
{
NSLog(#"movie finished playback error");
}
movieController=[aNotification object];
[[NSNotificationCenter defaultCenter]removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:movieController ];
}
how did you define the selector? It should be:
- (void)movieDidFinish:(NSNotification*)notification

MPMoviePlayerController Wont Disappear

I have been trying all day but for some reason on IOS6 im having so many issues with MPMoviePlayerController, it seemed people have had issues but not similar enough to mine:
The movie loads up and plays fine, when it completes the movie. I can loop the movie. The issue arises when I try to close and remove the movie like so:
If I add the controls to the Movie itself and hit the "Done" button, the movie sort of just pauses & never closes!
Any tips/ideas?
_moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackComplete:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_moviePlayerController];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackLoaded:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:_moviePlayerController];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackComplete:)
name:kMovieOverlayViewTapped
object:nil];
[self.view addSubview:_moviePlayerController.view];
_moviePlayerController.fullscreen = YES;
-
Now on Playback loaded:
- (void)moviePlaybackLoaded:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:_moviePlayerController];
_moviePlayerController.movieSourceType = MPMovieSourceTypeFile;
_moviePlayerController.controlStyle = MPMovieControlStyleDefault;
[_moviePlayerController prepareToPlay];
[_moviePlayerController.view setFrame:CGRectMake(38, 100, 250, 163)];
[_moviePlayerController play];
}
now to remove the video:
- (void)moviePlaybackComplete:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:_moviePlayerController];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerDidExitFullscreenNotification
object:_moviePlayerController];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kMovieOverlayViewTapped
object:nil];
[_moviePlayerController stop];
[_moviePlayerController.view removeFromSuperview];
_moviePlayerController = nil;

Resources