I want to start/stop timer(in main class) with switch(from menu class ),based in my code the timer start fire when switch is ON and doesn't stop when i turn switch OFF. Here is my code :
menu.h
#protocol FlipsideViewControllerDelegate;
#interface FlipsideViewController : UIViewController {
id <FlipsideViewControllerDelegate> delegate;
IBOutlet UISwitch *fireSwitch;
}
#property (assign)UISwitch* fireSwitch;
-(IBAction)autoFire;
menu.m
#import "FlipsideViewController.h"
#import "mainViewController.h"
#synthesize fireSwitch;
- (void)viewDidLoad
{
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
//[super viewDidLoad];
fireSwitch.on = [defs boolForKey:activateautoplay];
}
-(IBAction)autoFire {
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
[defs setBool:fireSwitch.on forKey:activateautoplay];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Main.h
#import "FlipsideViewController.h"
#define activateautoplay #"isactivateautoplay"
#interface mainViewController : UIViewController <FlipsideViewControllerDelegate> {
NSTimer *Autotimer;
}
-(void)updateImagePosition:(NSTimer*)mytimer;
Main.m
#import "mainViewController.h"
#sunthesize Autotimer;
- (void)awakeFromNib {
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
if ([defs boolForKey:activateautoplay]) {
self.Autotimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updateImagePosition:) userInfo:nil repeats:YES];
} else {
[self.Autotimer invalidate];
}
}
-(void)updateImagePosition:(NSTimer*)mytimer {
.....
}
If you don't mind introducing coupling between the two classes, you could always just give FlipsideViewController a reference to mainViewController and have it poke a method directly. Or you could have FlipsideViewController send an appropriate message to its delegate when the value is changed, which could then poke mainViewController.
But the best way from a standpoint of avoiding unnecessary coupling is to have mainViewController listen for NSUserDefaultsDidChangeNotification, which will automatically be sent when setBool:forKey: is called.
Requested edit:
In Main.m, add a method like this:
- (void)startOrStopTimer {
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
if ([defs boolForKey:activateautoplay]) {
if (!self.Autotimer) self.Autotimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updateImagePosition:) userInfo:nil repeats:YES];
} else {
[self.Autotimer invalidate];
self.Autotimer = nil;
}
}
Then change your awakeFromNib to something like this:
- (void)awakeFromNib {
[self startOrStopTimer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(startOrStopTimer) name:NSUserDefaultsDidChangeNotification object:nil];
}
And be sure to add this to dealloc:
[[NSNotificationCenter defaultCenter] removeObserver:self];
No changes are necessary to FlipsideViewController, and no settings bundle is needed.
Related
in my app there are two views. view1 has a function testing
-(void) testing
{
NSLog(#"Testing : %d", (++x));
}
and a timer
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(testing) userInfo:nil repeats:YES];
what i want, is to stop and run this timer from view2. How to do that ?
Define Timer in AppDelegate,
#interface TimerDemoAppDelegate : NSObject <UIApplicationDelegate>
{
NSTimer *timer;
}
#property (nonatomic, retain) NSTimer *timer;
#end
And use timer in your both view by creating TimerDemoAppDelegate object
in your view .h file
#interface View1 : UIViewController
{
TimerDemoAppDelegate *appDelegate;
}
in your view .m file
appDelegate=(TimerDemoAppDelegate *)[[UIApplication sharedApplication] delegate];
now use timer as appDelegate.timer.
Add timer2 to your View2 class
#interface View2 : UIView{
NSTimer *timer2;
}
#property (nonatomic,retain) NSTimer *timer2;
#end
#implementation View2
#synthesize timer2;
#end
and do like this
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(testing) userInfo:nil repeats:YES];
view2.timer2 = timer;
Using NSNotificationCenter you can call methods from another view without creating any objects.
In your viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(button:)
name:#"Next"
object:nil];
-(void)button:(NSNotification *) notification
{
// write a code of timer here.....
}
//call this following from another view
[[NSNotificationCenter defaultCenter]
postNotificationName:#"Next"
object:self];
Enjoy with this code....
I created a custom UISwitch for my iPhone app with NSUserDefaults and added a modal view controller (PincodeSetupViewController) for Pincode to setup. Here is the info the user will see:
When the user clicks to launch the app first time on the mainViewController shows UISwitch is already set to OFF because the user doesn't setup the Pincode. That is correct.
Next step is when the user decides to turn the switch to ON and it must display the modal view controller (PincodeSetupViewController) immediately. It slides from bottom to top. That is correct.
Now the user closed the app and opens it again. It shows the switch set to ON already because the user did this to setup Pincode. That is correct.
The user decided to turn the switch OFF and back to ON. When the switch is set to ON again, it displays the modal view controller (PincodeSetupViewController) immediately. The problem I have here is that the modal view controller doesn't transition slide from bottom to top, it just appears abruptly. This is not correct. I want that modal view controller to transition slide from bottom to top instead of abruptly.
Does anybody know what is wrong with it? Any suggestion appreciated.
mainViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
customSwitch = [[RCSwitchOnOff alloc] initWithFrame:CGRectMake(1.0, 0.0, 74, 40)];
[customSwitchView addSubview:customSwitch];
[customSwitch addTarget:self action:#selector(togglePincode:) forControlEvents:UIControlEventValueChanged];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"pincode"]) {
NSLog(#"SWITCH MESSAGE: ON");
[customSwitch setOn:YES];
} else {
NSLog(#"SWITCH MESSAGE: OFF");
[customSwitch setOn:NO];
}
}
- (void)togglePincode:(UISwitch *)sender {
if(sender.on){
NSLog(#"Switch is ON");
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:YES forKey:#"pincode"];
[userDefaults synchronize];
//Check to see if the user already setup the Pincode or not.
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"setupdone_status"]) {
NSLog(#"Display Pincode Setup");
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"setupdone_status"];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"PincodeSetupViewController"];
[vc setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentModalViewController:vc animated:YES];
} else {
NSLog(#"No Pincode Setup");
}
} else {
NSLog(#"Switch is OFF");
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:NO forKey:#"pincode"];
[userDefaults setBool:YES forKey:#"setupdone_status"];
[userDefaults synchronize];
}
}
AppDelegate.m I added some code in applicationDidEnterBackground and applicationWillTerminate methods
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"pincode"]) {
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"setupdone_status"];
} else {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"setupdone_status"];
}
I recreated your setup as best as I could and didn't get an error. Here is the code I used:
// ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
- (IBAction)switchChange:(id)sender;
#property (nonatomic, retain) NSNumber *valueOfSwitchON;
#property (weak, nonatomic) IBOutlet UISwitch *theSwitch;
#end
// ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize valueOfSwitchON;
#synthesize theSwitch;
- (void)viewDidLoad
{
[super viewDidLoad];
valueOfSwitchON = [NSNumber numberWithBool:NO];
// Do any additional setup after loading the view, typically from a nib.
}
- (void) viewDidAppear:(BOOL)animated
{
if ([valueOfSwitchON boolValue] == YES) [theSwitch setOn:YES];
else [theSwitch setOn:NO];
}
- (void)viewDidUnload
{
[self setTheSwitch:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (IBAction)switchChange:(id)sender
{
if ([self.valueOfSwitchON boolValue] == NO)
{
[self performSegueWithIdentifier:#"modalSegue" sender:self];
valueOfSwitchON = [NSNumber numberWithBool:YES];
}
else
{
valueOfSwitchON = [NSNumber numberWithBool:NO];
}
}
#end
// ViewController2.h
#import <UIKit/UIKit.h>
#interface ViewController2 : UIViewController
- (IBAction)closething:(id)sender;
#end
// ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)closething:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
#end
Storyboard:
I hope this helps (note that I just set up a lot of things purely in IB that you were creating programmatically)
I know this question as been asked over and over but it's still quite obscure to me, so I guess making an example with my code instead will probably be easier .
I know that you can use :
A global variable, ( not good practice ).
Use a delegate
Use a singleton
Say I've got this piece of code here in my first view controller header :
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController {
IBOutlet UITextField *Te;
NSInteger evTe;
}
#property (nonatomic, retain) UITextField *Te;
#property (nonatomic) NSInteger evTe;
- (IBAction) makeKeyboardGoAway;
#end
and then this in my implementation file
#import "FirstViewController.h"
#implementation FirstViewController
#synthesize Te;
- (IBAction) makeKeyboardGoAway;
{
[Te resignFirstResponder];
evTe = [Te.text intValue];
}
How would I call evTe in my SecondViewController ? ( maybe using a delegate ?) .
This is what I've got in the second view Controller, header :
#interface SecondViewController : UIViewController {
NSInteger evTe;
}
#property (nonatomic) NSInteger evTe;
and implementation :
- (IBAction) makeKeyboardGoAway;
{
FirstViewController *first = [[FirstViewController alloc] init];
first.evTe = self.evTe;
NSLog(#"second value is %i",evTe);
}
Thanks a lot !
Edit for Tob
FirstViewController.m
- (IBAction) makeKeyboardGoAway;
{
evTe = [Te.text intValue];
NSLog(#"The value of integer num is %i", evTe);
NSDictionary *changedValues = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:evTe] forKey:#"evTe"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"evTeChanged" object:self userInfo:changedValues];
}
SecondViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(methodToCall:) name:#"evTeChanged" object:nil];
}
- (void)methodToCall:(NSNotification *)aNotification{
NSDictionary *changedValues = [[aNotification userInfo] objectForKey:#"evTe"];
NSString *dictionaryString = [changedValues description];
NSLog(#"Notification returning %d",dictionaryString);
}
Unfortunately I'm not getting any log from the SecondView ..
By creating a #property called evTe or whatever in both view controllers.
If the FirstViewController is responsible for creating the SecondViewController you could store the value of evTe in a property in FirstViewController and then after you have created the SecondViewController you set the evTe property there as well.
- (IBAction) makeKeyboardGoAway;
{
[Te resignFirstResponder];
self.evTe = [Te.text integerValue];
}
// other method where SecondViewController is created
SecondViewController* second = [[SecondViewController alloc] init];
second.evTe = self.evTe;
// do what ever
--Edit--
#interface FirstViewController : UIViewController {
IBOutlet UITextField *Te;
NSInteger evTe;
}
#property (nonatomic, retain) UITextField *Te;
#property (nonatomic) NSInteger evTe;
Have a look at NSNotification. You should send a notification that the particular value has changed and register for that notification in the second view controller.
- (IBAction) makeKeyboardGoAway;
{
[Te resignFirstResponder];
evTe = [Te.text intValue];
NSDictionary *changedValues = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:evTe] forKey:#"evTe"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"evTeChanged" object:self userInfo:changedValues];
}
And in the viewDidLoad method of the other controller do:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(methodToCall:) name:#"evTeChanged" object:nil];
Now every time the first controller calls makeKeyboardGoAway the method - (void)methodToCall:(NSNotification *)aNotification will be called.
Implement this method and ask the aNotification for its userInfo which is the NSDictionary you created in the first controller before posting the notification. Get the evTe value out of it and do whatever you want to do with that value.
At first time i call the timer like this in Third viewcontroller
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(targetMethod) userInfo:nil repeats:NO];
Then timer called the targetMethod
-(void)targetMethod
{
First * sVC = [[First alloc] initWithNibName:#"First" bundle:[NSBundle mainBundle]];
[self presentModalViewController:sVC animated:YES];
[sVC release];
[timer invalidate];
}
First viewcontroller opened..
In First viewcontroller had one button.In button action
i wrote
- (IBAction) Action:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
Third *BVC=[[Third alloc]init];
[Bvc TimerStart]; //Timestart is function i start timer in this function..
//i want to call Third viewcontroller timer function this place
}
timer started..But view didn't open (first )viewcontroller.......
Please help me......
Bala,
Place the NSTimer object in the App Delegate .h file, include that .h file in wherever you use the timer. This will allow the NSTimer to be a global timer which you can call from any other view that includes the app delegate header file.
In app delegate .h file (in the appropriate areas):
NSTimer *delayTimer;
#property (nonatomic, retain) NSTimer *delayTimer;
Synthesize this in the app delegate .m file (remember to release it in dealloc):
#synthesize delayTimer;
Then in whichever views you use the timer in, access it like this:
// get global variable
SomeNameHereAppDelegate *mainDelegate = (SomeNameHereAppDelegate *)[[UIApplication sharedApplication] delegate];
mainDelegate.delayTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(targetMethod) userInfo:nil repeats:NO];
Then when you want to invalidate it from somewhere, you just do this:
[mainDelegate.delayTimer invalidate];
mainDelegate.delayTimer = nil;
What if if i need to have a count down timer which should be shared among the view controllers.do i have to make it in the app delegate where the remaining seconds could be an ivar also in app delegate with property?
In this case i would post notification from the timer handler after updating the remaining seconds
In AppDelegate.h
#property int timePassed;
In AppDelegate.m
#synthesize timePassed;
In ViewController.h
#property (weak, nonatomic)NSTimer *timer;
#property (weak, nonatomic) IBOutlet UILabel *time;
In ViewController.m
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
AppDelegate *delegate = (AppDelegate*) [[UIApplication sharedApplication] delegate];
delegate.timePassed = 180;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(TimePasses) userInfo:nil repeats:YES];;
}
-(void) TimePasses{
AppDelegate *delegate = (AppDelegate*) [[UIApplication sharedApplication] delegate];
delegate.timePassed = delegate.timePassed - 1;
NSLog(#"TimePasses %d", delegate.timePassed);
int minuts = delegate.timePassed / 60;
int seconds = delegate.timePassed - (minuts * 60);
NSString *timerOutput = [NSString stringWithFormat:#"%2d:%.2d", minuts, seconds];
time.text = timerOutput;
}
In SecondViewController.h
#property (weak, nonatomic)NSTimer *timer;
#property (weak, nonatomic) IBOutlet UILabel *time;
In SecondViewController.m
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(TimePasses) userInfo:nil repeats:YES];;
}
-(void) TimePasses{
AppDelegate *delegate = (AppDelegate*) [[UIApplication sharedApplication] delegate];
NSLog(#"TimePasses in 2 %d", delegate.timePassed);
int minuts = delegate.timePassed / 60;
int seconds = delegate.timePassed - (minuts * 60);
NSString *timerOutput = [NSString stringWithFormat:#"%2d:%.2d", minuts, seconds];
time.text = timerOutput;
}
in my app, an NSMutableArray is populated with an object in viewDidLoad (eventually there will be many objects but I'm just doing one til I get it working right). I also start a timer that starts a method that needs to access the NSMutableArray every few seconds. The NSMutableArray works fine in viewDidLoad, but as soon as that method is finished, it loses the object.
myApp.h
#interface MyApp : UIViewController {
NSMutableArray *myMutableArray;
NSTimer *timer;
}
#property (nonatomic, retain) NSMutableArray *myMutableArray;
#property (nonatomic, retain) NSTimer *timer;
#end
myApp.m
#import "MyApp.h"
#implementation MyApp
#synthesize myMutableArray;
- (void) viewDidLoad {
cycleTimer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:#selector(newCycle) userInfo: nil repeats:YES];
MyObject *myCustomUIViewObject = [[MyObject alloc]init];
[myMutableArray addObject:myCustomUIViewObject];
[myCustomUIViewObject release];
NSLog(#"%i",[myMutableArray count]); /////outputs "1"
}
-(void) newCycle {
NSLog(#"%i",[myMutableArray count]); /////outputs "0" ?? why is this??
}
myApp.m is not retaining the array unless you assign to it using self.myMutableArray, unless you use the self. prefix you do not get the benefit of the (nonatomic, retain).
Your results point to an array that is not allocated at the time you read from it. It's either this or failing to allocate the array before using addObject (unlikely given your NSLog result).
- (void) viewDidLoad {
self.myMutableArray = [NSMutableArray array];
...
}
would probably fix this up.
Try this
- (void) viewDidLoad {
cycleTimer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:#selector(newCycle) userInfo: nil repeats:YES];
MyObject *myCustomUIViewObject = [[MyObject alloc]init];
NSMutableArray *my_array = [[NSMutableArray alloc] initWithCapacity:3];
self.myMutableArray = my_array;
[my_array release];
[myMutableArray addObject:myCustomUIViewObject];
[myCustomUIViewObject release];
NSLog(#"%i",[myMutableArray count]); /////outputs "1"
}
and don't forget to
- (void) viewDidUnLoad {
self.myMutableArray = nil;
}
and
- (void) dealloc{
[myMutableArray release];
[super dealloc];
}