I have a floor in my logic, I'm struggling to find it. I have three buttons on my app which have two states, on and off. I have different images for each state, the buttons and image swapping is working well. My problem is on load, no matter what state the buttons are saved to, my buttons load to a selected state.
In my viewDidLoad I grab the states from memory:
NSString *_greyButtonSavedState = [[NSUserDefaults standardUserDefaults] stringForKey:#"greyButton"];
I then immediately check the state and apply the correct image (this isn't working):
if ([_greyButtonSavedState isEqualToString:#"ON"]) { [_greyButton setSelected:YES]; } else { [_greyButton setSelected:NO]; }
Each time the button is pressed I run the following:
- (IBAction) _greyButtonPress:(id)sender {
if ([sender isSelected]) {
NSLog(#"Grey map not created");
[sender setImage:_unselectedGrey forState:UIControlStateNormal];
[sender setSelected:NO];
//save state to memory
[[NSUserDefaults standardUserDefaults] setValue:#"OFF" forKey:#"greyButton"];
}else {
NSLog(#"Grey map created");
[sender setImage:_selectedGrey forState:UIControlStateSelected];
[sender setSelected:YES];
//save state to memory
[[NSUserDefaults standardUserDefaults] setValue:#"ON" forKey:#"greyButton"];
}
}
The logs show that on viewDidLoad the image being used is 'selected' but the button is in an 'unselected' mode. I have tried with and without:
[[NSUserDefaults standardUserDefaults] synchronize];
being called each time the button is pressed, no difference.
Any help would be great, thanks.
Well, I notice in one case you use UIControlStateNormal, but the other you use UIControlStateSelected. I think that is the source of your problem.
You are saying "If it is selected, set the image to unselected" and "If it is not selected, set the selected image to selected.
Related
I have a table view with user posts that can be upvoted and downvoted. I have two custom buttons for the upvote and downvote in the cells, which I use like so:
// in cellForRowAtIndexPath:
[cell.upVote addTarget:self action:#selector(handleThumbsUp:) forControlEvents:UIControlEventTouchUpInside];
[cell.downVote addTarget:self action:#selector(handleThumbsDown:) forControlEvents:UIControlEventTouchUpInside];
//the methods
- (IBAction)handleThumbsUp:(ThumbsUpButton *)sender {
if (sender.selected == YES) {
[sender setSelected:NO];
} else {
[sender setSelected:YES];
}
}
- (IBAction)handleThumbsDown:(ThumbsDownButton *)sender {
if (sender.selected == YES) {
[sender setSelected:NO];
} else {
[sender setSelected:YES];
}
}
When the "Thumbs Up" button is selected, and the user changes his mind and presses "Thumbs Down", how can I deselect the "Thumbs Up" button in that same cell?
You should have a model that contains the "thumbs up/down" information; you should not be storing it in your views in the form of the button being selected or not.
When one of the buttons is tapped, your controller should update the model and refresh the view based on the state of the model.
(Some kind of binding system would make this easier: ReactiveCocoa is one such option (though it's much more than just model/view bindings); another, much simpler (shameless link to my own free code) is my own UIViewController+WSSDataBindings category.)
By #selector you can access a property of the button not another control of the cell in a button handler method.
So, You must have update whole cell on the button handler method and manually handle the selected state of buttons in cellForRowAtIndexpath delegate method of table.
For simplest solution (with minimum structure change and code) it may be achieved with moving button action methods to your custom cell class. then add actions to upvote and downvote in cellForRowAtIndexPath:
// in cellForRowAtIndexPath:
[cell.upVote addTarget:cell action:#selector(handleThumbsUp:) forControlEvents:UIControlEventTouchUpInside];
[cell.downVote addTarget:cell action:#selector(handleThumbsDown:) forControlEvents:UIControlEventTouchUpInside];
Or you can directly set this methods from Nib file.
and then change the upvote / downvote methods like this.
//the methods
- (IBAction)handleThumbsUp:(ThumbsUpButton *)sender {
if (sender.selected == YES) {//upvote undone
[sender setSelected:NO];
} else {//upvote done
[self.upVote setSelected:YES];
[self.downVote setSelected:NO];//delesect downvote
}
}
- (IBAction)handleThumbsDown:(ThumbsDownButton *)sender {
if (sender.selected == YES) {//downVote undone
[sender setSelected:NO];
} else {
[self.downVote setSelected:YES];
[self.upVote setSelected:NO];//deselect upvote
}
}
also as Josh Caswell stated in his answer, you should have a data for the user's upvote and downvote in your dataModel you fill your cell. This is just a quick answer for this specific case, but to support dataModel changes you can add reference to your model inside your cell and modify it inside this action methods for saving votes.
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 am working on an app where I have multiple buttons on one page that you click on to go to a different view. The thing is I would like the user to click on them in a specific order. So basically, have all buttons locked except for one and then each time you click on a button that is enabled, it unlocks a new one.
Thanks.
You can do this easily via Tag
When you creating view at that time just put FirstButton in Enabled mode.
OnClick event on every UIButton you can Enabled next one.
For example
i created View with 4 UIButton and given tag 1,2,3,4 at ViewLoad only UIButton with Tag 1 is only Enabled
For all 4 UIButton i have created common Action method as follow which Enabled next UIButton with next Tag
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if([[NSUserDefaults standardUserDefaults] valueForKey:#"LastEnableButton"]){
UIButton * btnTemp = (UIButton *) [self.view viewWithTag:[[[NSUserDefaults standardUserDefaults]valueForKey:#"LastEnableButton"] intValue]];
[btnTemp setEnabled:YES];
NSLog(#"If you want to enable all button which are enabled previously then make for loop up to NSUserDefaults value from starting value");
}
}
- (IBAction)btn_click : (id)sender {
UIButton * btnTemp = (UIButton *) [self.view viewWithTag:([sender tag] + 1)];
if(btnTemp) {
if([btnTemp isKindOfClass:[UIButton class]]) {
[btnTemp setEnabled:YES];
[[NSUserDefaults standardUserDefaults]setValue:[NSNumber numberWithInt:([sender tag] + 1)] forKey:#"LastEnableButton"];
[[NSUserDefaults standardUserDefaults]synchronize];
}
}
}
I have a check box designed through a button and i am able to change the checkbox images but i am unable to save that last image that is checked in the checkbox when i click on Save button.
I have a page in which a check box is there and save button action is also there when i click on save the value in the checkbox must be saved and when i again re-enter in that screen the previous whatever the value in the checkbox must be seen, but for me every time when i enter into this screen the checkbox is seen empty.
Hope someone helps me out.
BOOL checked;
- (IBAction)canFollowAction:(id)sender
{
UIButton *tappedButton = (UIButton*)sender;
if([tappedButton.currentImage isEqual:[UIImage imageNamed:#"checkBox.png"]])
{
[sender setImage:[UIImage imageNamed:#"selected.png"] forState:UIControlStateNormal];
}
else
{
[sender setImage:[UIImage imageNamed:#"checkBox.png"]forState:UIControlStateNormal];
}
}
- (IBAction)btnSaveAction:(id)sender
{
if(checked)
{
[btnCheckCanFollow setImage:[UIImage imageNamed:#"selected.png"] forState:UIControlStateNormal];
}
else
{
[btnCheckCanFollow setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
}
[self.navigationController popViewControllerAnimated:YES];
[[[iToast makeText:#"Successfully Updated"]setGravity:iToastGravityBottom]show];
}
#kool kims - The term you used Save value. There any many ways to keep persistent data of your application.
Use NSUserDefaults to save values at application level.
Use .plist file
CoreData
SQlite
Document directory
As per your application architecture you can choose from above, which is more relevant and efficient for your application.
EDIT:
The simplest way if there are not more than one checkbox, You can use NSUserDefaults
Save check value when you click on Save button
- (IBAction)btnSaveAction:(id)sender
{
NSNumber *checkValue = [NSNumber numberWithBool:checked];
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
[standardDefaults setObject:checked forKey:#"kCheckBoxValue"];
[standardDefaults synchronize];
if(checked)
{
[btnCheckCanFollow setImage:[UIImage imageNamed:#"selected.png"] forState:UIControlStateNormal];
}
else
{
[btnCheckCanFollow setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
}
[self.navigationController popViewControllerAnimated:YES];
[[[iToast makeText:#"Successfully Updated"]setGravity:iToastGravityBottom]show];
}
Whenever you open that ViewController you get previous values from NSUserDefaults from -viewDidLoad or -viewWillAppear.
- (void)viewDidLoad {
[super viewDidLoad];
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
if ([standardDefaults objectForKey:#"kCheckBoxValue"]) {
NSNumber *checkValue = [standardDefaults objectForKey:#"kCheckBoxValue"];
checked = [checkValue boolValue];
} else {
checked = NO;
}
}
You Must Save the state in NSUSERDEFAULTS!
For Example ON Button Click
if (button.selected)
{
[button setSelected:YES];
[[NSUserDefaults standardUserDefaults]setObject:[NSNumber numberWithBool:YES] forKey:#"REMEMBER_ME"];
}
and check on ViewDidLoad
if([[NSUserDefaults standardUserDefaults] boolForKey:#"REMEMBER_ME"] == YES)
{
[button setSelected:YES];
[button setImage:[UIImage imageNamed:#"selected.png"] forState:UIControlStateSelected];
}
else
{
[button setSelected:NO];
[button setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
}
Take a global variable to strore the status of check box or in NSUserdefaults u can save the status of button. & chek this status on viewdidload method of controller.
According to what I understood Lets take an example
#property (weak, nonatomic) IBOutlet UIButton *yourButton;
and its Implementation Action
- (IBAction)yourMethodName:(UIButton *)sender {
int tag=_yourButton.tag; //if you have tagged your UI button save it to know which button has changed its state.
if(sender.isSelected){ //Checking state of the button whether selected or not.
UIImage *buttonImage=sender.currentImage;//save this image if your selected images randomly.
NSString *buttonText=sender.currentTitle;//gets you current text in button.
}else{
//selected state is NO
//checkBox is Off.
}
}
here I have showed how you can get different values you need only to store your state as I believe your working with one button/checkbox and you can populate your image based on that state.
However if you have multiple checkboxes or UIbutton you may want to Tag each UIButton your using
[_yourButton setTag:1];
and store tag value too inside action method using sender.tag
EDIT:
Just now went through your code
BOOL checked; value is never set or stored.
so everytime if condition fails.
Also If you have multiple UIButtons you may want to store checked state and tag for the UIButton as I have mentioned earlier;