I want to delay this button for 23 hours, which is 82800 seconds. It should work fine, the button does delay after one click, however when I switch to another view controller, or re-enter the application, the button delay function fails to work as it just pops back to clickable button after switching to another view controller or re-starting the application.
here is the code:
- (IBAction)save:(id)sender
{
UIButton *theButton = (UIButton *) sender;
theButton.enabled = NO;
[self performSelector:#selector(enableButton:) withObject:theButton afterDelay:82800.0];
}
- (void)enableButton:(UIButton *)button
{
button.enabled = YES;
}
I am looking for the code that allows this button to be delayed for 23 hours, no matter if I quit the application or switch to another view controller.
please help
You should use NSUserDefaults. When save: method is called check current date [NSDate date] and save it into the user defaults. Then (when time has already passed) you retrieve the saved date from the defaults and compare it to the current date. If 23 hours have already passed you enable the button
UPDATED:
this how you save the date:
- (IBAction)save:(id)sender
{
UIButton *theButton = (UIButton *) sender;
theButton.enabled = NO;
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:#"savedDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
then (in future) you fetch the saved date:
NSDate* savedDate = [[NSUserDefaults standardUserDefaults] objectForKey:#"savedDate"];
if ([[NSDate date] timeIntervalSinceDate:savedDate] >= 82800.0 )
{
theButton.enabled = YES;// you need to keep the reference to the button
}
Related
I am facing an issue that my segmented controller is not saving its position after closing the application and opening it again.
My code is as per below:
- (void)viewDidLoad {
[super viewDidLoad];
[self.segmentedControlButtonStyle addTarget:self action:#selector(changeButtonStyle:) forControlEvents:UIControlEventValueChanged];
}
- (IBAction)changeButtonStyle:(id)sender {
NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.number.application"];
NSInteger selectedSegmentedControlerIndex = self.segmentedControlButtonStyle.selectedSegmentIndex;
if (sharedDefaults) {
[sharedDefaults setInteger: selectedSegmentedControlerIndex forKey:#"MySelectedButtonStyleKey"];
[sharedDefaults synchronize];
}
}
The funny thing is that NSUserDefaults actually is saving correct index because from method I provided above if I change button style it will keep changed after closing and opening application again because I can see it by fact but segmented controller itself is not showing correct segment.
I am not sure why this is happening because I am synchronizing after each segment change but still segmented controller keeps its default position.
in view did load you should add code to set your saved segment
NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.number.application"];
int mySegment = [sharedDefaults integerForKey:#"MySelectedButtonStyleKey"];
if(mySegment) {
self.segmentedControlButtonStyle.selectedSegmentIndex = mySegment;
}
I have a UISwitch set as the accessoryView in each of my TableView cells.
If I press my Confirm button, I want to save the state of each UISwitch with NSUserDefaults. Then when I leave and go back to that View Controller, I should be able to load those saved states which will be different for each cell (either on or off, as shown in image).
I'm almost there but I guess I am not sure how to save/load with the right indexPath.row so it's not working correctly. Right now it is just saving/loading one BOOL value only, so if I save one cell with the switch ON, then all of them will be ON, and vice versa.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
BOOL menuSwitchState = [[NSUserDefaults standardUserDefaults] boolForKey:#"menuItemSwitch"];
NSLog(#"Menu Switch State is: %#", menuSwitchState ? #"Yes": #"No");
[self.switchView setOn:menuSwitchState animated:YES];
}
UISwitch code in my cellForRowAtIndexPath:
// Add a UISwitch to the accessory view.
self.switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = self.switchView;
self.switchView.tag = indexPath.row;
self.switchView.on = [[NSUserDefaults standardUserDefaults] boolForKey:#"menuItemSwitch"];
[self.switchView addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
Switch action method which sets a BOOL:
- (void) switchChanged:(id)sender {
UISwitch *switchControl = sender;
NSLog(#"The switch's tag number is %ld", (long)switchControl.tag);
// NSLog(#"The switch is %#", switchControl.on ? #"ON" : #"OFF" );
if ([sender isOn])
{
self.switchIsOn = YES;
NSLog(#"THE SWITCH IS ON");
}
else
{
self.switchIsOn = NO;
NSLog(#"THE SWITCH IS OFF");
}
}
Confirm button that should save the state of the switch:
#pragma mark - UIBUTTONS
- (IBAction)onConfirmMenuButtonPressed:(id)sender
{
[self performSegueWithIdentifier:#"segueMenuToGettingStarted" sender:self];
//TODO: Save state of Switch.
if (self.switchIsOn == YES)
{
[[NSUserDefaults standardUserDefaults] setBool:self.switchView.on forKey:#"menuItemSwitch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
else
{
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
[ud setBool:NO forKey:#"menuItemSwitch"];
}
}
You save that value just like any other value you use in a table view -- in an array that's your data source. Given what you show in your image, your data source should be an array of dictionaries with keys for the menu item, price, and switch state. In cellForRowAtIndexPath, you would set the state of the switch based on the value ( a BOOL) in your array.
in your code, you just set one NSUserDefault value for the all items(now, looks like three), I think you must separate each kind of item, it means you must have the count of NSUserDefault same as the count of UISwitch, In UIViewController, you can hold the NSUserDefault values in an Array, when you change the switch, you changed the cell data, when you leave the ViewController, save the Array's values. Enter the ViewController, update the Array.
I need help trying to do a crude type of confirmation where you need to type: I got it! into a NSTextField then press button1 so that once they do press button1 I make my button2 enabled using
-(IBAction)check:(id)sender{
NSString *string = [NSString stringWithValue:#"I Got It!"];
if(field.stringValue isEqualToString:string){
[field setHidden:YES];
[button1 setHidden:YES];
[button2 setEnabled:YES]
}
}
This is only a one-time confirmation so I'm wondering how I can save the state of the button so that next time they launch the app they don't have to do the confirmation again. The textfield and button1 will be hidden and so that button2 will always be enabled, I want to use the NSUserDefaults because I think that would be the easiest for me to understand.
You can use as below
if ([[NSUserDefaults standardUserDefaults]
boolForKey:#"ishidden"] != YES){
// First launch
} else { //not first launch }
Have a look at NSUserDefaults Class Reference. You can use - (void)setBool:(BOOL)value forKey:(NSString *)defaultName
I have a view controller containing 2 text fields, 2 segmented controls and a few labels which display time stamps set by the user using UIButtons. I would like to be able to restore any user set values for these items upon quit / restart, as well as when going back to my main menu view controller, which is a navigation controller. Using the following code, I am able to restore one of the text fields on background / terminate / restart, but I am unsure as to how to accomplish this for my other text field or the time stamp labels and segmented controls. I have tried to duplicate the restoration code with changes for the text field name and the #"UnsavedText" string with no luck.
Furthermore, whenever I go back to the main menu using the back button in the navigation bar, I lose all of my data from all fields.
Here is the code in my delegate, opting in to state restoration:
// Sets RESTORATION
-(BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
return YES;
}
-(BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
return YES;
}
Here is the relevant code in my view controller to restore the one text field. I am including my viewDidLoad code with state initialization in case that is somehow part of the problem:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// Updates time on currentTimeLabel
[self updateTime];
// Sets initial button states
[self setInitialState];
// Sets UITextField delegate
self.startLevel.delegate = self;
self.stopLevel.delegate = self;
// initializes basic values for segmented controls
bigTank = YES;
startFractions = #"";
stopFractions = #"";
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// Restoration of text fields
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
// start level text
[coder encodeObject:_startLevel.text forKey:#"UnsavedText"];
[super encodeRestorableStateWithCoder:coder];
}
-(void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
// start level text
_startLevel.text = [coder decodeObjectForKey:#"UnsavedText"];
[super decodeRestorableStateWithCoder:coder];
}
// Sets initial button and label states
- (void)setInitialState
{
self.start.enabled = YES;
self.stop.enabled = NO;
self.calculate.enabled = NO;
self.resume.enabled = NO;
// Text for time labels reset
_startTimeLabel.text = #"- -:- -:- -.- -";
_stopTimeLabel.text = #"- -:- -:- -.- -";
// Resets the minuteRateLabel
_minuteRateLabel.text = #"--.--";
// Resets the text fields to their initial state with the placeholder "inches" text
[_startLevel setText:nil];
[_stopLevel setText:nil];
// Resets inch levels to EVEN
[self.startFractionControl setSelectedSegmentIndex:0];
[self.stopFractionControl setSelectedSegmentIndex:0];
startFractions = #"";
stopFractions = #"";
}
Thanks in advance!
EDIT:
This is the code I tried per the suggestion:
My button click should ostensibly save the time stamp value:
- (IBAction)startButton:(UIButton *)sender
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"hh:mm:ss.SS"];
_startTimeLabel.text = [formatter stringFromDate:[NSDate date]];
UIButton *startButton = (UIButton *)sender;
// Creates the start time stamp for use in the calculation
startTime = [NSDate timeIntervalSinceReferenceDate];
// sets button states
startButton.enabled = NO;
stop.enabled = YES;
// Hides keypad on startButton click
[self.startLevel resignFirstResponder];
[self.stopLevel resignFirstResponder];
// saves the value for restoration using user defaults
NSDateFormatter *startTimeSave = formatter;
[[NSUserDefaults standardUserDefaults]
setObject:startTimeSave forKey:#"startTimeSaver"];
}
You can save your text values using user defaults. Here is a sample code snippet:
NSString *valueToBeSaved = #"someValue";
[[NSUserDefaults standardUserDefaults]
setObject:valueToBeSaved forKey:#"preferenceName"];
And for retrieving your value later, use this:
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"preferenceName"];
I've got two UITextFields, the input of which I store into strings player1 and player2. These UITextFields are on a ViewController called by a popOver segue. How can I make the UITextFields keep displaying their text once the view has changed?
I tried textFieldOne.text = player1; in the viewDidLoad section of the ViewController to no avail. Any ideas?
If your loaded view's delegate isn't ViewController, your code wouldn't be executed. So be sure that your code is on the delegate of the loaded view. Use also [textFieldOne setText:player1]. It's always better to call the setter method instead of setting the ivar directly. Then be sure that your UITextField is not nil and correctly binded. Use textFieldOne = [[UITextField alloc] init] to initialise it. If your problem continues, try also [textFieldOne setText:self.player1]. Hope it helps..
EDIT :
Got the solution here. You should use NSUserDefaults so your player names are stored and can be used in each view and even after re-opening your app (if you don't want this you can erase the defaults at lunch. Here is your bunch of code you need to change :
hardOne.m :
- (void)viewDidLoad
{
[super viewDidLoad];
[hard1ON setOn:switchState animated:NO];
//read player names to user defaults
[textFieldOne setText:[[NSUserDefaults standardUserDefaults] stringForKey:#"player1"]];
[textFieldTwo setText:[[NSUserDefaults standardUserDefaults] stringForKey:#"player2"]];
}
- (IBAction) returnKey1
{
player1 = [textFieldOne text];
[players addObject:(player1)];
//set player1's name to user defaults
[[NSUserDefaults standardUserDefaults] setValue:[textFieldOne text] forKey:#"player1"];
}
- (IBAction) returnKey2
{
player2 = [textFieldTwo text];
[players addObject:(player2)];
NSLog(#"array: %#",players);
//set player2's name to user defaults
[[NSUserDefaults standardUserDefaults] setValue:[textFieldTwo text] forKey:#"player2"];
}