NSNotification in Cocos2d iphone - iphone

i have a button in the start screen of my game,when the user tap the button it will redirected to the next page, i calling a notification in this button click event ,the code for this is
- (void)switchsounds
{
CCLOG(#"hiii");
[[NSNotificationCenter defaultCenter] postNotificationName:#"reloadvieweyes" object:nil];
CCTransitionJumpZoom *transition = [CCTransitionJumpZoom transitionWithDuration:1.0 scene:[HelloWorldLayer scene]];
// Tell the director to run the transition
[[CCDirector sharedDirector] replaceScene:transition];
}
the above code is the button click function
on the next page of init statmnet i put this code to get the functonalty of the button event
-(id) init
{
if( (self=[super init])) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(viewreloadedeyes) name:#"reloadvieweyes" object:nil];
}
return self;
}
-(void)viewreloadedeyes
{
CCLOG(#"hiii");
}
i didnt get the cclog in button click event aswell as the function in the next page.but the page redirction is done with the button lcick.what is the problm with my code.how to get nsnofication from one page to anothe in a button click.
Thanks in advance.

Notification selectors require the NSNotification* parameter. Change your code to this:
-(id) init
{
if( (self=[super init])) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(viewreloadedeyes:)
name:#"reloadvieweyes"
object:nil];
}
return self;
}
-(void)viewreloadedeyes:(NSNotification*)notification
{
CCLOG(#"hiii");
}

heyy guys,i found the solution, i just put the notification inside the view transtion like this
- (void)switchsounds
{
CCLOG(#"hiii");
CCTransitionJumpZoom *transition = [CCTransitionJumpZoom transitionWithDuration:1.0 scene:[HelloWorldLayer scene]];
[[NSNotificationCenter defaultCenter] postNotificationName:#"reloadvieweyes" object:nil];
// Tell the director to run the transition
[[CCDirector sharedDirector] replaceScene:transition];
}
now its woking perfectly.Thanks.

Related

Resume AVPlayer video playback after app become active

I write custom player from AVPlayer for video playback. According to Apple docs set the video layer:
self.player = [IPLPlayer new];
self.player.playerLayer = (AVPlayerLayer *)self.playerView.layer;
Where self.playerView is usual class from those docs:
#implementation PlayerView
+ (Class) layerClass {
return [AVPlayerLayer class];
}
- (AVPlayer *)player {
return [(AVPlayerLayer *)[self layer] player];
}
- (void)setPlayer:(AVPlayer *) player {
[(AVPlayerLayer *) [self layer] setPlayer:player];
}
The problem is:
When close app (Home button), or block screen, the video playback is stopped, and when resume ONLY audio playback resumed, the image on screen is still those was before block screen - it's fully static and note change frames.
How to resume VIDEO playing after screen is blocked?
Seems I must to register notifications, and after app become active resume video layer:
-(void)registerNotification
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(willEnterBackground)
name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didEnterForeground)
name:UIApplicationDidBecomeActiveNotification object:nil];
}
-(void)unregisterNotification
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void)willEnterBackground
{
NSLog(#"willEnterBackground");
[self.playerView willEnterBackground];
}
-(void)didEnterForeground
{
NSLog(#"didEnterForeground");
[self.playerView didEnterForeground];
}
And one solution that binds all this information together.
Maybe player status should be handled differently, but I like the recursive way.
Note: If you do not need the exact seek time, you can use [_player seekToTime:<#(CMTime)#> completionHandler:<#^(BOOL finished)completionHandler#>] It's faster but it seeks to the nearest key frame.
- (void)viewDidLoad
{
[super viewDidLoad];
....
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appEnteredForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appEnteredBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
-(void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}
....
-(void) appEnteredForeground {
AVPlayerLayer *player = (AVPlayerLayer *)[playerView layer];
[player setPlayer:NULL];
[player setPlayer:_player];
[self playAt:currentTime];
}
-(void) appEnteredBackground {
[_player pause];
currentTime = [_player currentTime];
}
-(void)playAt: (CMTime)time {
if(_player.status == AVPlayerStatusReadyToPlay && _player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
[_player seekToTime:time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
[_player play];
}];
} else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self playAt:time];
});
}
}
This works for me on Swift 3
Add somewhere while setting up the view:
NotificationCenter.default.addObserver(self,
selector: #selector(appWillEnterForegroundNotification),
name: .UIApplicationWillEnterForeground, object: nil)
Grab your player and force it to play:
func appWillEnterForegroundNotification() {
myPlayer.play()
}
Don't forget to remove the observers when you don't need them:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
Use the UIApplicationWillEnterForegroundNotification as well. That way you know your app will be active and visible to the user:
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(appEnteredForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
The trick is to detach all video layers from their players when the app did enter background and reattaching them when the app did become active again.
So in your -applicationDidEnterBackground: you got to trigger a mechanism that results in
avPlayerLayer.player = nil;
and in your -applicationDidBecomeActive: you reattach the player like
avPlayerLayer.player = self.avPlayer;
Also have a look at this Tech Note (QA1668) from Apple.
After some research I've found, that the same bag is in iOS player (WebBrowser, MPMoviePlayerController). May be because distribution type of content is Progressive Download.
So solution is:
Use below notifications and save current time.
After app is resumed, recreate AVPlayer and start playing from saved
time.
In all other cases image is blocked, or view become black.

How to send object in NSNotification?

I want to send object to selector in NSNotification.I mean, I have 3 buttons and on click of each button I am registering notification and when that event occurred I am calling one selector and in that selector I want to find out which button user has clicked because I have common action for all 3 buttons.
-(void)allThreeButtonAction:(sender)id
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(performSomeOperationWhenEventOccur) name:#"EventCompletedNotification" object:nil];
}
//Some event occurred, so I am sending notification
[[NSNotificationCenter defaultCenter] postNotificationName:#"EventCompletedNotification" object:nil];
//Notified method
-(void)performSomeOperationWhenEventOccur
{
//Here I want to know which button is pressed.
}
I hope I am clear.
You may want to look at postNotificationName:object:userInfo: from NSNotificationCenter documentation
You simply send a UserInfo containing whatever you need to identify the button (easiest is the pointer to the button) that you retrieve in your selector.
Your selector signature should receive the notification:
- (void)performSomeOperationWhenEventOccur:(NSNotification*) notification:(NSNotification*) notification
{
// Use [notification userInfo] to determine which button was pressed...
}
Don't forget to modify the selector name when your register it:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(performSomeOperationWhenEventOccur:) name:#"EventCompletedNotification" object:nil];
You can't pass an object when adding a notification observer, so you'll have to store the button that was pressed somewhere:
-(void)allThreeButtonAction:(id)sender
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(performSomeOperationWhenEventOccur) name:#"EventCompletedNotification" object:nil];
self.buttonPressed = sender;
}
Then you can just read it in your notification handler:
-(void)performSomeOperationWhenEventOccur
{
if ( self.buttonPressed = self.button1 )
...
}
Below Snippet will help you.
Button1
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(performSomeOperationWhenEventOccur:) name:#"button1" object:button1];
Button2
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(performSomeOperationWhenEventOccur:) name:#"button2" object:button2];
Change method to following
- (void) performSomeOperationWhenEventOccur:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"button1"])
{
NSButton *button1=[notification button1];
NSLog (#"Successfully received the test notification! from button1");
}
else
{
NSButton *button2=[notification button2];
NSLog (#"Successfully received the test notification! from button2");
}
}

how to add done button in keypad

i need to add button done on keypad.
Apple does n't provide such felicity but some of application i found that done ,next,previous buttons.
like this.
how can i add these and how can i give click event to them.
can any one please help me.
1.Define the done button (= return key):
textField.returnKeyType = UIReturnKeyDone;
2.Add the action-listener:
[textField addTarget:self action:#selector(textFieldDoneEditing:) forControlEvents:UIControlEventEditingDidEndOnExit];
3.Define the action-event:
- (IBAction)textFieldDoneEditing:(id)sender {
[sender resignFirstResponder];
}
Have fun!
EDIT:
Here you can find detailed instructions how to add a Toolbar with Next & Previous above UITextField Keyboard:
http://www.randomsequence.com/articles/adding-a-toolbar-with-next-previous-above-uitextfield-keyboard-iphone/
EDIT2:
Now, I have a really great example for you: "This view extends UITextView adding on top of the keyboard associated with this UITextView a toolbar with a « Done » Button"
I check the code and it is a lot of easier than the first example:
http://blog.demay-fr.net/2009/07/cocoa-how-to-add-a-toolbar-with-button-on-top-of-a-uitextview-in-order-to-add-a-dismiss-button/
EDIT3:
Hmmm, no, I doesn't test to code. But I will test it now!
1.Problem: the right initialization. If I add the UITextView in IB, initWithCoder gets called:
- (id)init {
NSLog(#"init");
if (self = [super init]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
NSLog(#"initWithCoder");
if (self = [super initWithCoder:decoder]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
NSLog(#"initWithFrame");
if (self = [super initWithFrame:frame]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
2.Problem: There's no view with the the Prefix "UIKeyboard":
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
NSLog(#"keyboardWindow = %#", keyboardWindow);
for (UIView *keyboard in [keyboardWindow subviews]) {
NSLog(#"keyboard = %#", keyboard);
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES) {
// THERE'S NO VIEW 'UIKeyboard'!!!
}
}
}
The code doesn't work, I'm sorry... I don't know why there's no view "UIKeyboard"... Maybe the first example will help you at this point and you can build your own solution.

Is it possible to check if done button is pressed

I have notification on movie player:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
And it's handler:
- (void) moviePlayBackDidFinish:(NSNotification*)notification
{
[[UIApplication sharedApplication] setStatusBarHidden:YES];
// Remove observer
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
[self dismissModalViewControllerAnimated:YES];
}
Here in this handler method I want to check if the done button is sender. Because I have two senders to this method. How ti check this?
Per docs: MPMoviePlayerPlaybackDidFinishNotification userInfo dictionary must contain NSNUmber for MPMoviePlayerPlaybackDidFinishReasonUserInfoKey key indicating the reason playback has finished. Its possible values:
enum {
MPMovieFinishReasonPlaybackEnded,
MPMovieFinishReasonPlaybackError,
MPMovieFinishReasonUserExited
};
You will first need to assign tag to your buttons before the action and then check the value of the sender tag.
Just add these lines of code:
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
NSInteger anyInteger = [sender tag];
//Now check the value of the anyInteger and write the code accordingly.
//switch case or if condition whatever you want.
}
That's it.
This is an old thread but I stumbled upon it while looking for a solution, and the accepted solution doesn't show the final code.
Here is what you have to do:
- (void) moviePlayBackDidFinish:(NSNotification*)notification
{
NSLog(#"moviePlayBackDidFinish");
// Remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
NSInteger movieFinishReason= [[[notification userInfo]objectForKey:
MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
if(movieFinishReason == 2 || movieFinishReason == 1 || movieFinishReason == 0){
[self dismissViewControllerAnimated:YES completion:nil];
}
/*
MPMovieFinishReasonPlaybackEnded = 0,//played movie sucessfuly.
MPMovieFinishReasonPlaybackError = 1, //error in playing movie
MPMovieFinishReasonUserExited = 2; //user quitting the application / user pressed done button
*/
}
Add tag with the button and put condition according to the tag.
Or check by
if([sender isEqual:btn1])
{
}
else
{
}

Properly displaying and dismissing fullscreen MPMoviePlayerController in iOS 3.2 (iPad)

I'm having lots of trouble displaying a fullscreen movie in my iPad app and then allowing the user to dismiss it with either the Done button or the "un-fullscreen" button on the player controls.
Initially I was using MPMoviePlayerViewController for the movie presentation, but I wasn't receiving the enter/exit fullscreen notifications from its MPMoviePlayerController object, so I switched to doing it myself.
I can make the movie appear fullscreen (although the transition is janky), but when either the "Done" or "un-fullscreen" buttons are pressed, no action is taken by the player. I've posted my code below:
- (void)startPlayingMovieWithURLString:(NSString *)movieURLString {
// I get all of these callbacks **EXCEPT** the "willExitFullScreen:" callback.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterFullScreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willExitFullScreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didFinishPlayback:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
[self.moviePlayerController setContentURL:someExistingURL];
// "self" is a UIViewController subclass, and is presented as a "fullscreen" modal view controller from its parent
// I'm setting the movie player's view's frame to take up the full rectangle of my view controller, but really I want the movie to be completely removed when the user presses "done" (that is, removed from the view hierarchy). Not sure when/where to do this.
self.moviePlayerController.view.frame = self.view.frame;
[self.view addSubview:self.moviePlayerController.view];
[self.moviePlayerController setFullscreen:YES animated:YES];
}
And here is the code for my didFinish callback
- (void)didFinishPlayback:(NSNotification *)notification {
// This ends up recursively telling the player that playback ended, thus calling this method, thus…well you get the picture.
// What I'm trying to do here is just make the player go away and show my old UI again.
[self.moviePlayerController setFullscreen:NO animated:YES];
}
So obviously I am doing something wrong but I've been up and down the documentation and I can't figure out how to make the movie just go away. I figured it would be more intuitive than this. What am I doing wrong?
Here are how the events -> notifications work:
User presses 'Done' button
MPMoviePlayerWillExitFullscreenNotification
MPMoviePlayerDidExitFullscreenNotification
User presses 'Leave fullscreen' button on transport
MPMoviePlayerWillExitFullscreenNotification
MPMoviePlayerDidExitFullscreenNotification
Note that playback does not stop
Movie reaches end
MPMoviePlayerPlaybackDidFinishNotification with the MPMoviePlayerPlaybackDidFinishReasonUserInfoKey set to MPMovieFinishReasonPlaybackEnded
If you call setFullscreen:NO animated:YES on your MoviePlayerController instance from this notification, you'll then get the WillExit and DidExit notifications.
Note that you don't get the PlaybackDidFinish notification when the user presses the Done or Leave Fullscreen buttons.
So, typically, if you want to get rid of the MoviePlayer's view, you need to put [self.moviePlayerController.view removeFromSuperview] in the DidExitFullscreen notification handler. WillExitFullscreen is too soon.
Here's my code:
- (void)willEnterFullscreen:(NSNotification*)notification {
NSLog(#"willEnterFullscreen");
}
- (void)enteredFullscreen:(NSNotification*)notification {
NSLog(#"enteredFullscreen");
}
- (void)willExitFullscreen:(NSNotification*)notification {
NSLog(#"willExitFullscreen");
}
- (void)exitedFullscreen:(NSNotification*)notification {
NSLog(#"exitedFullscreen");
[self.movieController.view removeFromSuperview];
self.movieController = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)playbackFinished:(NSNotification*)notification {
NSNumber* reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
switch ([reason intValue]) {
case MPMovieFinishReasonPlaybackEnded:
NSLog(#"playbackFinished. Reason: Playback Ended");
break;
case MPMovieFinishReasonPlaybackError:
NSLog(#"playbackFinished. Reason: Playback Error");
break;
case MPMovieFinishReasonUserExited:
NSLog(#"playbackFinished. Reason: User Exited");
break;
default:
break;
}
[self.movieController setFullscreen:NO animated:YES];
}
- (void)showMovie {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willExitFullscreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enteredFullscreen:) name:MPMoviePlayerDidEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(exitedFullscreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
NSURL* movieURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"tron" ofType:#"mov"]];
self.movieController = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
self.movieController.view.frame = self.view.frame;
[self.view addSubview:movieController.view];
[self.movieController setFullscreen:YES animated:YES];
[self.movieController play];
}
Yes. That's great. There are really notifications mentioned above...
However, there are no MPMoviePlayerPlaybackWillFinishNotification somewhy!!!
That's really a problem.
When you call the movie player as modal (no matter which of the following methods used presentViewController/presentModalViewController/presentVideoController), if you defined .fullScreen = YES, it's not expected to call MPMoviePlayerWillExitFullscreenNotification notification at all (obviously, because it's not cosidering we enter/exit from full screen, but only present/dismiss the controller).
But there are really no any notifications that the video is about to finish and close. That's needed (besides any other situations possible) to catch the moment when the transition of dismissing is started. (The transition, of course, starts before the MPMoviePlayerPlaybackDidFinishNotification called). And, at the same time, application:supportedInterfaceOrientationsForWindow: for previously shown controller is called before the notification, and there is no way to say the AppDelegate that our current controller must be shown already in another orientation.
So, since my video is fullscreen and also without any controls shown (this is kind of an intro, so I just until it finishes) my solution was just to have a timer which checks every short tick (0.1 seconds) what is the video current position... and it it's close to the end, then this is the moment for my own notification.