NSNotificationCenter with arguments - ios4

I am implementing an Audio based application. In that I am playing two different sounds using two AVPlayers. I need to do different actions once the sounds played. For this I used NSNotifications. But my problem is I am not able to find the Notifications related to which player. My notifications code and selector code is as follows please any one suggest me what the mistake I did.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playingItemDidEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:iPodPlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playingItemDidEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:applicationPlayer ];
- (void)playingItemDidEnd:(NSNotification *)notification
{
id object= [notification object];
if(object==ipodPlayer)
{
printf("\n Notification from iPod Player ");
}
else if(object==applicationPlayer)
{
printf("\n Notification from application Player ");
}
}
Thanks in advance,
Chandra.

I need to change the code base as follows,
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playingItemDidEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[applicationPlayer currentItem] ];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playingItemDidEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[iPodPlayer currentItem]];
And selector code should be as follows,
- (void)playingItemDidEnd:(NSNotification *)notification
{
AVPlayerItem* object= [notification object];
if(object==[applicationPlayer currentItem])
{
}
else if(object==[avPlayer currentItem])
{
}
}

Related

Rotate youtube video with iOS8

I am having a problem with rotate youtube video. I added the following code to my app. And it works for iOS 7. However, it doesn't for iOS8.
In my view controller, I used the following code:
if(IS_OS_6_OR_LATER){
// I use the following notification for iOS 7
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeStarted:) latername:#"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];//Notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeFinished:) name:#"UIMoviePlayerControllerWillExitFullscreenNotification" object:nil];//Notification
}
if (IS_OS_8_OR_LATER) {
// I use the following notification for iOS 8
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeStarted:) name:UIWindowDidBecomeVisibleNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeFinished:) name:UIWindowDidBecomeHiddenNotification object:self.view.window];
}
-(void) youTubeStarted:(NSNotification*) notif {
//Handle event
AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.fullScreenVideoIsPlaying = YES;
NSLog(#"start fullscreen");
}
-(void) youTubeFinished:(NSNotification*) notif {
AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];//Notification
appDelegate.fullScreenVideoIsPlaying = NO;//Notification
NSLog(#"exit fullscreen");//Notification
}
-(BOOL) shouldAutorotate {
//Handle rotate
NSLog(#"AutoState");
return NO;
}
-(NSUInteger)supportedInterfaceOrientations{
//Handle rotate
NSLog(#"AutoState 1");
return UIInterfaceOrientationMaskPortrait;//Notification
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
//Handle rotate
NSLog(#"AutoState 2");
return UIInterfaceOrientationPortrait;//Notification
}
In iOS 7, when video is played in Landscape mode, I press Done button, I see log 'AutoState 1' is shown however I don't see this log when running with iOS 8. Can you help me resolve this on iOS 8? Thank you very much
Instead of limiting the entire app to Portrait and then trying to make the video player allow landscape, you should instead allow landscape all over your app and then limit your invididual view controllers (or the root view controller) to only allow Portrait mode, like this:
In the target settings, allow landscape for your app:
In your view controller(s), add this to limit it to portrait orientation:
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}

How to observe the value of an NSTextField

This might seem straightforward, but the following code does not work, because the "observeValueForKeyPath" function is never called, although I keep changing the text in the NSTextfield:
- (void)awakeFromNib
{
[myNSTextField addObserver:self forKeyPath:#"value" options:NSKeyValueObservingOptionOld context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(#"observeValueForKeyPath");
}
The log message #"observeValueForKeyPath" is never printed. I tried observing the key #"stringValue", but this does not work neither...
Am I missing something ??
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(textFieldDIdChange:)
name:NSControlTextDidChangeNotification
object:self.textField];
[[NSNotificationCenter defaultCenter] addObserverForName:NSTextViewDidChangeSelectionNotification
object:self.textView
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note){
NSLog(#"Text: %#", self.textView.textStorage.string);
}];

Core Data and multithreading (and Bindings to make it more fun)

I have got this background thread that does a few things with core data objects. I get the context as follows:
- (id)_managedObjectContextForThread;
{
NSManagedObjectContext * newContext = [[[NSThread currentThread] threadDictionary] valueForKey:#"managedObjectContext"];
if(newContext) return newContext;
newContext = [[NSManagedObjectContext alloc] init];
[newContext setPersistentStoreCoordinator:[[[NSApplication sharedApplication] delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(_mergeChangesFromManagedObjectContext:)
name:NSManagedObjectContextDidSaveNotification
object:newContext];
[[[NSThread currentThread] threadDictionary] setValue:newContext forKey:#"managedObjectContext"];
return newContext;
}
then I fetch some objects, modify them and save the context:
- (void) saveContext:(NSManagedObjectContext*)context {
NSError *error = nil;
if (![context save:&error]) {
[[NSApplication sharedApplication] presentError:error];
}
}
- (void)_mergeChangesFromManagedObjectContext:(NSNotification*)notification;
{
[[[[NSApplication sharedApplication] delegate] managedObjectContext] performSelectorOnMainThread:#selector(mergeChangesFromContextDidSaveNotification:)
withObject:notification
waitUntilDone:YES];
}
.. later I remove the observer. This works for the main part. But some properties don't get updated when they get merged back. The properties that were nil before get updated. The ones that had a value stay the same.
I tried:
[newContext setMergePolicy:NSOverwriteMergePolicy];
... (and the other merge policies) on the main context but it did not work :P
Thank you for your help.
Note: I have bound the values to a NSTableView. I log them after the merge. The values properties that were nil seem to work fine.
How are you registering both contexts for notifications? You need to do something like this:
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(backgroundContextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:backgroundMOC];
[nc addObserver:self
selector:#selector(mainContextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:mainMOC];
And implement the callbacks:
// merge changes in background thread if main context changes
- (void)mainContextDidSave:(NSNotification *)notification
{
SEL selector = #selector(mergeChangesFromContextDidSaveNotification:);
[backgroundMOC performSelector:selector onThread:background_thread withObject:notification waitUntilDone:NO];
}
// merge changes in main thread if background context changes
- (void)backgroundContextDidSave:(NSNotification *)notification
{
if ([NSThread isMainThread]) {
[mainMOC mergeChangesFromContextDidSaveNotification:notification];
}
else {
[self performSelectorOnMainThread:#selector(backgroundContextDidSave:) withObject:notification waitUntilDone:NO];
}
}

NSNotification Does Not Notify

I have an application that shows a lot of videos. To load and play the file, I use the following code:
- (IBAction)playVideoooo {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:
[NSURL URLWithString:#"/UnioneDiCentro2011_Live.isml/manifest(format=m3u8-aapl)"]];
switch ( [self interfaceOrientation] ) {
case UIInterfaceOrientationPortrait:
case UIInterfaceOrientationPortraitUpsideDown:
[[moviePlayerController view] setFrame:CGRectMake(0, 0, P_WIDTH, P_HEIGHT)];
break;
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
[[moviePlayerController view] setFrame:CGRectMake(0, 0, L_WIDTH, L_HEIGHT)];
break;
}
[moviePlayerController prepareToPlay];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateChanged:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil]; // Register that the load state changed (movie is ready)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
[[self view] addSubview:[moviePlayerController view]];
}
- (void)moviePlayerLoadStateChanged:(NSNotification*)notification {
// Unless state is unknown, start playback
if ([moviePlayerController loadState] != MPMovieLoadStateUnknown) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
[[UIApplication sharedApplication] setStatusBarOrientation:[self interfaceOrientation]
animated:YES];
[moviePlayerController play];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
}
- (void)moviePlayBackDidFinish:(NSNotification*)notification {
[[UIApplication sharedApplication] setStatusBarHidden:NO];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
switch ( [self interfaceOrientation] ) {
case UIInterfaceOrientationPortrait:
case UIInterfaceOrientationPortraitUpsideDown:
[[moviePlayerController view] setFrame:CGRectMake(0, 0, P_WIDTH, P_HEIGHT)];
break;
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
[[moviePlayerController view] setFrame:CGRectMake(0, 0, L_WIDTH, L_HEIGHT)];
break;
}
if ( [moviePlayerController isFullscreen] ) {
[moviePlayerController setFullscreen:NO];
}
}
Actually the system seems to works, but I have to push the button linked to "playVideooooo" two times, to let the notification work. If I move the [moviePlayerController play]; into the IBActions the video starts correctly. How should I get the Notifications work?
Question partially solved: the matter is not in the NSNotification but in PrepareToPlay.

MPMoviePlayerController causes flash of black at start of video

The movie plays just fine but there is a quick black flash right before it plays. Is this a quirk resulting from setting the controlstyle to MPMovieControlStyleNone?
NSString *url = [[NSBundle mainBundle] pathForResource:#"00" ofType:#"mov"];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc]
initWithContentURL:[NSURL fileURLWithPath:url]];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
//---play video in implicit size---
player.view.frame = CGRectMake(80, 64, 163, 246);
[self.view addSubview:player.view];
// Hide video controls
player.controlStyle = MPMovieControlStyleNone;
//---play movie---
[player play];
I just had this problem and fixed it by adding an observer to the default NSNotificationCenter to find out when the movie was completely ready to play, and THEN adding the view as a subview to my main view.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkMovieStatus:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
...
if(moviePlayer.loadState & (MPMovieLoadStatePlayable | MPMovieLoadStatePlaythroughOK))
{
[pageShown.view addSubview:moviePlayer.view];
[moviePlayer play];
}
In IOS 6 mpmoviewplayer added a new property :readyForDisplay
this is what I'm playing around with and so far so good:
create mpmovieplayer ,add to stage, hide it.
add notification for play state on the movieController
wait for the displayState to Change and once its ready show the video controller:
- (void)moviePlayerPlayState:(NSNotification *)noti {
if (noti.object == self.movieController) {
MPMoviePlaybackState reason = self.movieController.playbackState;
if (reason==MPMoviePlaybackStatePlaying) {
[[NSNotificationCenter defaultCenter] removeObserver:self name: MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
while (self.movieController.view.hidden)
{
NSLog(#"not ready");
if (self.movieController.readyForDisplay) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
NSLog(#"show");
self.movieController.view.hidden=NO;
});
}
usleep(50);
}
});
}
}
}
When the play state changes to MPMoviePlaybackStatePlaying we start checking for the readyDisplayState to change.
Evidently there is a flash of black in the movie rect until enough movie loads so it can start playback. Here is my workaround:
Create a UIImageView and put the MPMoviePlayerController in it. That way you can set the alpha to 0.
As soon as you call [player play]; to play the video, set up a .5 second timer.
When the time is done, change the alpha to 1.
This will make the player invisible for 1/2 second (which hides the black flash).
Create video without addSubview and play instructions:
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"video" ofType:#"mp4"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
MPMoviePlayerController *moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
[moviePlayerController.view setFrame:CGRectMake(80, 64, 163, 246)];
moviePlayerController.controlStyle = MPMovieControlStyleNone;
Prepare video to play and add notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkMovieStatus:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
[moviePlayerController prepareToPlay];
Create function checkMovieStatus with addSubview and play instructions:
- (void)checkMovieStatus:(NSNotification *)notification {
if(moviePlayerController.loadState & (MPMovieLoadStatePlayable | MPMovieLoadStatePlaythroughOK)) {
[self.view addSubview:moviePlayerController.view];
[moviePlayerController play];
}
}
Or simply change the color of the view, that is what your actually seeing...
player.view.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0];
I believe the black flash may be related to the movieSourceType property of MPMoviePlayerController.
If you don't set it, it defaults to MPMovieSourceTypeUnknown which causes the UI to be delayed until the file is loaded.
Try adding this line:
player.movieSourceType = MPMovieSourceTypeFile;
Right after initializing player.
To avoid the black flash, use a MPMoviePlayerViewController instead of a MPMoviePlayerController. I think that this class creates the background on view display, rather than on video load (like MPMoviePlayerController does).
Before adding the moviePlayerViewController.moviePlayer.view to your display view, you have to add a white subview (or a subview appropriate for your content) to the backgroundView, like this:
[moviePlayerViewController.moviePlayer.view setFrame:[displayView bounds]];
UIView *movieBackgroundView = [[UIView alloc] initWithFrame:[displayView bounds]];
movieBackgroundView.backgroundColor = [UIColor whiteColor];
[moviePlayerViewController.moviePlayer.backgroundView addSubview:movieBackgroundView];
[movieBackgroundView release];
Fond solution here http://joris.kluivers.nl/blog/2010/01/04/mpmovieplayercontroller-handle-with-care/
from iOS 6
you need to use [self.moviePlayer prepareToPlay]; and catch MPMoviePlayerReadyForDisplayDidChangeNotification to use [self.moviePlayer play];

Resources