invalidate and fire Timer from different view controller is not working - iphone

myTimer is defined in OneViewController and i m trying to invalidate and fire it again from mainviewcontroller but it is not working. What exactly i m missing here.
here is my code
OneViewController.h
#property (nonatomic, strong) NSTimer *myTimer;
OneViewController.m
#synthesize myTimer;
- (void)viewDidLoad
{
[super viewDidLoad];
[self myTimerMethod];}
- (void)myTimerMethod{
NSLog(#"myTimerMethod is Called");
self.myTimer = [NSTimer scheduledTimerWithTimeInterval:2.4
target:self
selector:#selector(updateView:)
userInfo:nil
repeats:YES];
}
- (void)updateView:(NSTimer *)theTimer
{
if (index < [textArray count])
{
self.textView.text = [self.textArray objectAtIndex:index];
self.imageView.image = [self.imagesArray objectAtIndex:index];
index++;
}else{
index = 0;
}
}
MainViewController.h
#class OneViewController;
#property (strong, nonatomic) OneViewController *oneviewcontroller;
MainViewController.m
#synthesize oneviewcontroller = _oneviewcontroller;
-(void)playpauseAction:(id)sender {
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"music.png"] forState:UIControlStateNormal];
[audioPlayer pause];
[self.oneviewcontroller.myTimer invalidate];
}else{
[sender setImage:[UIImage imageNamed:#"audiostop.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self.oneviewcontroller.myTimer fire];
if(isFirstTime == YES)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:06.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO; } } }
- (void)displayviewsAction:(id)sender{
OneViewController *oneviewcontroller = [[OneViewController alloc] init];
oneviewcontroller.view.frame = CGRectMake(0, 0, 320, 430);
CATransition *transitionAnimation = [CATransition animation];
[transitionAnimation setDuration:1];
[transitionAnimation setType:kCATransitionFade];
[transitionAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
[self.view.layer addAnimation:transitionAnimation forKey:kCATransitionFade];
[self.view addSubview:oneviewcontroller.view];
}
Appreciate help.
Thanks.

You create OneViewController as a local variable of the method displayviewsAction. Not as the property you defined previously.
That's why it's not working, the variable gets released once you exit the method.
Change this line:
OneViewController *oneviewcontroller = [[OneViewController alloc] init];
With this one:
self.oneviewcontroller = [[OneViewController alloc] init];

Related

No Known class method for selector 'myTimer'

Have basically two view controllers oneviewcontroller and mainviewcontroller. In oneviewcontroller defined myTimer. In mainviewcontroller i m trying to pause and resume myTimer using UIButton. But getting message No Known class method for selector 'myTimer'
In OneViewController defined NSTimer as myTimer
#property (nonatomic, retain) NSTimer *myTimer;
#synthesize myTimer;
- (void)viewDidLoad {
[self myTimerMethod];
[super viewDidLoad];
}
- (void)myTimerMethod{
NSLog(#"myTimerMethod is Called");
myTimer = [NSTimer scheduledTimerWithTimeInterval:2.4
target:self
selector:#selector(updateView:)
userInfo:nil
repeats:YES];
}
- (void)updateView:(NSTimer *)theTimer
{
if (index < [textArray count])
{
self.textView.text = [self.textArray objectAtIndex:index];
self.imageView.image = [self.imagesArray objectAtIndex:index];
index++;
}else{
index = 0;
}
I m trying to pause and resume myTimer from mainviewcontroller
In mainviewcontroller.h
#class OneViewController;
#property (strong, nonatomic) OneViewController *oneviewcontroller;
#synthesize oneviewcontroller = _oneviewcontroller;
-(void)playpauseAction:(id)sender {
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"music.png"] forState:UIControlStateNormal];
[audioPlayer pause];
[[OneViewController myTimer] invalidate]; **\\No Known class method for selector 'myTimer'**
}else{
[sender setImage:[UIImage imageNamed:#"audiostop.png"] forState:UIControlStateNormal];
[audioPlayer play];
[[OneViewController myTimer] fire]; **\\No Known class method for selector 'myTimer'**
if(isFirstTime == YES)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:06.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO; } } }
how can i fix this error.
Thanks for help.
Instead of [[OneViewController myTimer] invalidate]; use [self.oneviewcontroller.myTimer invalidate];
Also, in OneViewController implementation, instead of myTimer = [NSTimer scheduledTimerWithTimeInterval:..... use self.myTimer = [NSTimer scheduledTimerWithTimeInterval:.....

Connection between two UIButtons programmatically

Connected rewindButton with playButton programmatically. rewindButton is simply rewinding and playing from the beginning and playButton toggles from play to pause.In the rewindButton method used statement to change the UIImage of UIButton2 when UIButton1 is pressed. That is working fine.
PlayButton method is working fine when play button is pressed and paused. Even after resuming is working fine.
Issue briefing:
When rewindButton is pressed it will change the UIImage of playButton to PauseImage so that user can pause. Problem arises when pause is resumed. When pause is resumed it is reloading view controllers.It should load viewcontrollers only for the first time as per code.
-(void)rewind:(id)sender{
audioPlayer.currentTime = 0;
[timer invalidate];
ContainerViewController *viewController = [[[ContainerViewController alloc] init]autorelease];
viewController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:viewController.view];
[self.view addSubview:toolbar];
[audioPlayer play];
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
[_playButton setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
}
-(void)playpauseAction:(id)sender {
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
[self pauseLayer:self.view.layer];
}else{
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
[self resumeLayer:self.view.layer];
if(isFirstTime == YES)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO;
}
}
}
- (void)displayviewsAction:(id)sender
{
First *first = [[First alloc] init];
first.view.frame = CGRectMake(0, 0, 320, 425);
CATransition *transitionAnimation = [CATransition animation];
[transitionAnimation setDuration:1];
[transitionAnimation setType:kCATransitionFade];
[transitionAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
[self.view.layer addAnimation:transitionAnimation forKey:kCATransitionFade];
[self.view addSubview:first.view];
[first release];
self.timer = [NSTimer scheduledTimerWithTimeInterval:23 target:self selector:#selector(Second) userInfo:nil repeats:NO];
}
-(void)Second
{
Second *second = [[Second alloc] init];
second.view.frame = CGRectMake(0, 0, 320, 425);
CATransition *transitionAnimation = [CATransition animation];
[transitionAnimation setDuration:1];
[transitionAnimation setType:kCATransitionReveal];
[transitionAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
[self.view.layer addAnimation:transitionAnimation forKey:kCATransitionReveal];
[self.view addSubview:second.view];
[second release];
self.timer = [NSTimer scheduledTimerWithTimeInterval:27 target:self selector:#selector(Third) userInfo:nil repeats:NO];
}
Reason it was reloading view controllers after resuming cause in the rewind method i forgot to add isFirstTime == YES for loading view controllers. Viewcontrollers are not required to reload. Viewcontrollers are required to start loading from the beginning only for the first time only.
So after setting the value of isFirstTime == YES in rewind method now it is not reloading view controllers from the beginning after it is resumed from the pause.
-(void)rewind:(id)sender{
audioPlayer.currentTime = 0;
[timer invalidate];
ContainerViewController *viewController = [[[ContainerViewController alloc] init]autorelease];
viewController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:viewController.view];
[self.view addSubview:toolbar];
[audioPlayer play];
if(isFirstTime == YES){
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO;
}
[_playButton setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
}
Now it is working fine.

Loading view controllers one after the other with delay in a container view

Loading multiple view controllers one after the other with delay like this
-(void)playpauseAction:(id)sender {
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
[self pauseLayer:self.view.layer];
}else{
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
[self resumeLayer:self.view.layer];
if(isFirstTime == YES)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO;
}}}
- (void)displayviewsAction:(id)sender
{
First *firstController = [[First alloc] init];
firstController.view.frame = CGRectMake(0, 0, 320, 480);
CATransition *transitionAnimation = [CATransition animation];
[transitionAnimation setDuration:1];
[transitionAnimation setType:kCATransitionFade];
[transitionAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
[self.view.layer addAnimation:transitionAnimation forKey:kCATransitionFade];
[self.view addSubview:firstController.view];
[self.view addSubview:toolbar];
[firstController release];
self.timer = [NSTimer scheduledTimerWithTimeInterval:23 target:self selector:#selector(Second) userInfo:nil repeats:NO];
}
-(void)Second
{
Second *secondController = [[Second alloc] init];
secondController.view.frame = CGRectMake(0, 0, 320, 480);
CATransition *transitionAnimation = [CATransition animation];
[transitionAnimation setDuration:1];
[transitionAnimation setType:kCATransitionReveal];
[transitionAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
[self.view.layer addAnimation:transitionAnimation forKey:kCATransitionReveal];
[self.view addSubview:secondController.view];
[self.view addSubview:toolbar];
[secondController release];
self.timer = [NSTimer scheduledTimerWithTimeInterval:27 target:self selector:#selector(Third) userInfo:nil repeats:NO];
}
Requirement is to add a container view and load all view controllers in containerview.
So, in the load view can create uiview and container view like this
- (void)loadView
{
// set up the base view
CGRect frame = [[UIScreen mainScreen] applicationFrame];
UIView *view = [[UIView alloc] initWithFrame:frame];
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
view.backgroundColor = [UIColor blueColor];
// set up content view a bit inset
frame = CGRectInset(view.bounds, 0, 100);
_containerView = [[UIView alloc] initWithFrame:frame];
_containerView.backgroundColor = [UIColor redColor];
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[view addSubview:_containerView];}
In the AppDelegate can do it like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ContainerViewController *container = [[ContainerViewController alloc] init];
self.window.rootViewController = container;
// make an array of 23 PageVCs
NSMutableArray *controllers = [NSMutableArray array];
[controllers addObject:firstcontroller];
[controllers addObject:secondcontroller];
[controllers addObject:.....];
[controllers addObject:twentythreecontroller];
for (int i=0; i<23; i++)
{
First *firstController = [[First alloc] init];
[controllers addObject:firstcontroller, secondcontroller, .....,twentythreecontroller];
}
// set these as sub VCs
[container setSubViewControllers:controllers];
[self.window makeKeyAndVisible];
return YES;}
Loading all viewcontrollers in container view like this will be okay or doing something wrong in here.
Appreciate help for this.
Thanks.
Firstly remove nstimer and use performSelector:withObject:afterDelay: method like this:
// add delay and method according to your requirement
[self performSelector:#selector(oneView) withObject:nil afterDelay:10];
-(void)oneView
{
//add firstView and perform second selector
[self performSelector:#selector(secondView) withObject:nil afterDelay:10];
}
-(void)secondView
{
//add secondView and perform thirdselector
[self performSelector:#selector(thirdView) withObject:nil afterDelay:10];
}
goes on .......................

Reference of UIImageview layer created in separate class

Defined resumeLayer and PauseLayer method within the #interface and #end block in h file.
#interface MainViewController : UIViewController
#property (nonatomic, retain) UIToolbar *toolbar;
#property (strong)AVAudioPlayer *audioPlayer;
#property (nonatomic, retain) NSTimer * timer;
- (void)resumeLayer:(CALayer *)layer;
- (void)pauseLayer:(CALayer *)layer;
#end
methods in m file
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
For calling resumeLayer and PauseLayer method in PlayPauseAction method
-(void)playpauseAction:(id)sender {
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
[self pauseLayer:ImageView.layer]; // Pause the CALayer of the UIImageView
}else{
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
if(isFirstTime == YES){
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO;
}
}
}
ImageView is defined in class named Third
- (void)viewDidLoad
{
// Displays UIImageView
UIImageView* ImageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 5, 300, 235)];
self.view.backgroundColor = [UIColor brownColor];
// load all the frames of our animation
ImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"3a.png"],
[UIImage imageNamed:#"3b.png"],
nil];
// all frames will execute in 24 seconds
ImageView.animationDuration = 24;
// start animating
[ImageView startAnimating];
ImageView.layer.borderWidth = 2;
ImageView.layer.borderColor = [[UIColor whiteColor]CGColor];
[ImageView.layer setMasksToBounds:YES];
[ImageView.layer setCornerRadius:15.0f];
[self.view addSubview:ImageView]; }
I want to get reference of this ImageView.layer in MainViewController class to use in
[self pauseLayer:ImageView.layer];
to pause imageview.layer animation
Now how can i get reference of this ImageView using
UIImageView *myImageView = [OtherClass getTheImageView];
to use following in playpauseAction to pause and resume Imageview layer animation
[self pauseLayer:myImageView.layer]; // Pause the CALayer of the UIImageView
Any one can help me with thisHow to reference ImageView.layer in MainviewController
Either you add a property to MainviewController and let ImageView set its value when it's ready, or you use NSNotificationCenter to send a notification from MainViewController to ImageView;
In ImageView:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pauseMyLayer) name:kPauseLayerNotif object:nil];
In MainViewController:
[[NSNotificationCenter defaultCenter] postNotificationName:kPauseLayerNotif object:self];
The notification mechanism provides you a very loose coupling between the two classes and it is very easy to use.

How to resume updating views when resumed AVAudioplayer

I m struggling with this issue for so long but not able to find any solution for this
The issue i have is when i pause the audioplayer i want views to be paused from updating so i used timer invalidate to pause the views from loading but when i resume play only Audioplayer is resumed not the views cause i invalidated the timer.
Now i how i can resume updating views from that point where view was paused. By starting the timer again i can start updating views again but how program will know that at what view it was paused and it should resume updating views from that point. There are multiple views involved displayed code for only two.
-(void)playpauseAction:(id)sender
{
if
([audioPlayer isPlaying]){
[sender setImage:[UIImage imageNamed:#"play.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[timer invalidate];
} else {
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
self.timer = [NSTimer scheduledTimerWithTimeInterval:11 target:self selector:#selector(displayviewsAction:) userInfo:nil repeats:NO];
}
}
- (void)displayviewsAction:(id)sender
FirstViewController *viewController = [[FirstViewController alloc] init];
viewController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:viewController.view];
[self.view addSubview:toolbar];
[viewController release];
self.timer = [NSTimer scheduledTimerWithTimeInterval:23 target:self selector:#selector(secondViewController) userInfo:nil repeats:NO];
-(void)secondViewController {
SecondViewController *secondController = [[SecondViewController alloc] init];
secondController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:secondController.view];
[self.view addSubview:toolbar];
[secondController release];
self.timer = [NSTimer scheduledTimerWithTimeInterval:27 target:self selector:#selector(ThirdviewController) userInfo:nil repeats:NO];
}
Thanks and appreciate for your answers and helping me out with this issue.
Use a background thread to basically bind the view to the player, something like this:
UIImageView* imageView; //the view that gets updated
int current_selected_image_index = 0;
float time_for_next_image = 0.0;
AVAudioPlayer* audioPlayer;
NSArray* image_times; //an array of float values representing each
//time when the view should update
NSArray* image_names; //an array of the image file names
-(void)update_view
{
UIImage* next_image_to_play = [image_names objectAtIndex:current_selected_image_index];
imageView.image = next_image_to_play;
}
-(void)bind_view_to_audioplayer
{
while(audioPlayer.isPlaying)
{
float currentPlayingTime = (float)audioPlayer.currentTime;
if(currentPlayingTime >= time_for_next_image)
{
current_selected_image_index++;
[self performSelectorOnMainThread:#selector(update_view) withObject:nil waitUntilDone:NO];
time_for_next_image = [image_times objectAtIndex:[current_selected_image_index+1)];
}
[NSThread sleep:0.2];
}
}
-(void)init_audio
{
current_selected_image_index = 0;
time_for_next_image = [image_times objectAtIndex:1];
}
-(void)play_audio
{
[audioPlayer play];
[self performSelectorInBackground:#selector(bind_view_to_audioplayer) withObject:nil];
}
-(void)pause_audio
{
[audioPlayer pause];
//that's all, the background thread exits because audioPlayer.isPlaying == NO
//the value of current_selected_image_index stays where it is, so [self play_audio] picks up
//where it left off.
}
also, add self as observer for the audioPlayerDidFinishPlaying:successfully: notification to reset when the audioplayer finishes playing.