NSButton Toggle Button change programmatically - objective-c

I have an NSButton set as a toggle (on/off) in my application. When I click the button it works fine, but when I try and programmatically set it using [toggleButton setEnabled:YES]; it has no effect.
code:
- (void)awakeFromNib {
defaults = [NSUserDefaults standardUserDefaults];
NSString *toggleValue = [[NSUserDefaults standardUserDefaults] objectForKey:#"toggleActive"];
if (toggleValue == nil) toggleValue = #"YES";
if ([toggleValue isEqualToString:#"YES"]) {
[defaults setObject:#"YES" forKey:#"toggleActive"];
isOn = YES;
[toggleButton setEnabled:YES];
}
if ([toggleValue isEqualToString:#"NO"]) {
[defaults setObject:#"NO" forKey:#"toggleActive"];
isOn = NO;
[toggleButton setEnabled:NO];
}
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (IBAction)toggleButton:(id)sender {
if( isOn ) {
[self stopFunction: (NSButton *)sender];
isOn = NO;
[defaults setObject:#"NO" forKey:#"toggleActive"];
} else {
[self startFunction (NSButton *)sender];
isOn = YES;
[defaults setObject:#"YES" forKey:#"toggleActive"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
}
*toggleActive YES or NO get's stored in NSUserDefaults (which works fine); I'm wanting to remember the last button state when the user re-opens the application.

setEnabled: only changes the availability of the button to user interaction
The following will switch the button's image along with setting the button's state to on/off
[toggleButton setState:NSOnState];
[toggleButton setState:NSOffState];
If you would like to have the appropriate action to be taken along with the state change, you will have to call the appropriate functions as well
[toggleButton setState:NSOnState];
[self startFunction:toggleButton];
Alternatively, you can call
[toggleButton performClick:self];
However, this will cause a brief aqua blue shading of the button (like you are actually clicking on it) while it switches state. I prefer the former method on account of this.
All this is just made on some quick observations I made a little while ago, while trying to do the same thing (googling brought me to this thread). Hope this helps :)

Related

Switch Between 2 UIViewControllers in a NavigationBar Underneath

I have built a UIViewController to contain two other UIViewControllers. What I would like to do using a UISegment in the UINavigationBar is to switch between both views. When the user is finished they click on "Done" and it goes back to the RootViewController. I got this to work except the UIViewControllers take the size of the whole screen so the top portion is covered by the UINavigationBar. They don't adjust to the space under the UINavigationBar. I have been trying different techniques without success.
I have already tried in the ChildUIViewControllers without success
self.edgesForExtendedLayout = UIRectEdgeNone;
Here is my code:
RootViewController Calls the Container
ContainerController *controller = [[ContainerController alloc] init]
[self.navigationController pushViewController:controller animated:YES];
Container Code
- (void)viewDidLoad {
[super viewDidLoad];
UIViewController *vc = [self getCurrentViewController]; // Returns Current ViewController to Display
[self addChildViewController:vc];
vc.view.frame = self.view.bounds;
[self.view addSubview:vc.view];
self.currentViewController = vc;
}
-(UIViewController *)getCurrentViewController{
UIViewController *vc;
switch ([[NSUserDefaults standardUserDefaults] integerForKey:#"currentView"]) {
case kView1:{
vc = (ViewController1 *)[[ViewController1 alloc] init];
}break;
case kView2:{
vc = (ViewController2 *)[[ViewController2 alloc] init];
}break;
}
return vc;
}
- (void)segmentedControlIndexChanged:(id)sender{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[NSNumber numberWithInt:[sender selectedSegmentIndex]] forKey:#"currentView"];
[userDefaults synchronize];
UIViewController *vc = [self getCurrentViewController];
[self addChildViewController:vc];
[self transitionFromViewController:self.currentViewController toViewController:vc duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[self.currentViewController.view removeFromSuperview];
vc.view.frame = self.view.bounds;
[self.view addSubview:vc.view];
} completion:^(BOOL finished) {
[vc didMoveToParentViewController:self];
[self.currentViewController removeFromParentViewController];
self.currentViewController = vc;
}];
self.navigationItem.title = vc.title;
}
Anybody know what the problem is? Thanks.
I found a solution. The reason that the tableview was under the navigationbar was due to the translucence of the navigation bar. When I set this:
self.navigationController.navigationBar.translucent = NO;
The views remained under the navigation bar. There was still a black bar above the UITableView I fixed that problem by instead of using a UITableViewController I user a UIViewController and added a tableView. Here is some code to make cycle between the two views in the container uiviewcontroller:
- (void)viewDidLoad {
self.viewController1 = [[ViewController1 alloc] init];
self.viewController2= [[ViewController2 alloc] init];
switch ([[NSUserDefaults standardUserDefaults] integerForKey:#"dataView"]) {
case kDataView:{
self.viewController1.view.hidden=YES;
self.viewController2.view.hidden=NO;
}break;
case kChartView:{
self.viewController1.view.hidden=NO;
self.viewController2.view.hidden=YES;
}break;
}
[self.view addSubview:self.viewController1.view];
[self.view addSubview:self.viewController2.view];
}
- (void)segmentedControlIndexChanged:(id)sender{
if ([[NSUserDefaults standardUserDefaults] integerForKey:#"dataView"]!=[sender selectedSegmentIndex]){
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[NSNumber numberWithInteger:[sender selectedSegmentIndex]] forKey:#"dataView"];
[userDefaults synchronize];
self.segmentedControl.selectedSegmentIndex=[[NSUserDefaults standardUserDefaults] integerForKey:#"dataView"];
switch (self.segmentedControl.selectedSegmentIndex) {
case kDataView:{
self.viewController1.view.hidden=YES;
self.viewController2.view.hidden=NO;
}break;
case kChartView:{
self.viewController1.view.hidden=NO;
self.viewController2.view.hidden=YES;
}break;
}
}
}

AVAudioPlayer for Sprite Kit

I'm utilizing AVAudioPlayer in MyScene - the main game scene in my Sprite Kit game. I also have an OptionsScene containing 2 buttons. 1 of the buttons is for switching music ON/OFF.
Everything works except pressing the button doesn't instantly turn music ON or OFF. I have to leave the app, double-tap iPhone's Home button & swipe-up the game View to turn it off completely.
Once that is done, I can open the game & the previously selected ON/OFF button takes effect. Is there a way to have AVAudioPlayer turn off instantly upon clicking it's button in the options scene?
I do use a custom class for playing the music that I did not write. So I don't completely understand how it works. Here is the method I use inside MyScene to activate the AVAudioPlayer:
-(void)musicPlayer
{
defaults = [NSUserDefaults standardUserDefaults]; //"Activate" defaults.
music = [defaults boolForKey:#"MusicButtonKEY"]; //Then assign that defaults to a BOOL (music in this case).
if (music == YES) //Check what defaults BOOL key value was set to & act accordingly to that.
{
[self.audioController tryPlayMusic]; //tryPlayMusic is a method from AudioController class.
NSLog(#"Music playing");
}
else /*if (music == NO)*/
{
[self.audioController stopPlayingMusic]; //stopPlayingMusic is a method from AudioController class.
NSLog(#"Music not playing");
}
}
Here is the .h & .m files of the AudioController class:
AudioController.h
#import <Foundation/Foundation.h>
#interface AudioController : NSObject
-(instancetype)init;
-(void)tryPlayMusic;
-(void)stopPlayingMusic;
#end
AudioController.m
#import "AudioController.h"
#import AVFoundation;
#interface AudioController () <AVAudioPlayerDelegate>
#property (strong, nonatomic) AVAudioSession *audioSession;
#property (strong, nonatomic) AVAudioPlayer *backgroundMusicPlayer;
#property (assign) BOOL backgroundMusicPlaying;
#property (assign) BOOL backgroundMusicInterrupted;
#end
#implementation AudioController
#pragma mark - Public
-(instancetype)init
{
self = [super init];
if (self)
{
[self configureAudioSession];
[self configureAudioPlayer];
}
return self;
}
-(void)tryPlayMusic
{
//If background music or other music is already playing, nothing more to do here
if (self.backgroundMusicPlaying || [self.audioSession isOtherAudioPlaying])
{
return;
}
// Play background music if no other music is playing and we aren't playing already
//Note: prepareToPlay preloads the music file and can help avoid latency. If you don't
//call it, then it is called anyway implicitly as a result of [self.backgroundMusicPlayer play];
//It can be worthwhile to call prepareToPlay as soon as possible so as to avoid needless
//delay when playing a sound later on.
[self.backgroundMusicPlayer prepareToPlay];
[self.backgroundMusicPlayer play];
self.backgroundMusicPlaying = YES;
}
-(void)stopPlayingMusic
{
if (self.backgroundMusicPlaying == YES)
{
[self.backgroundMusicPlayer stop];
self.backgroundMusicPlaying = NO;
}
}
#pragma mark - Private
-(void)configureAudioSession
{
//Implicit initialization of audio session.
self.audioSession = [AVAudioSession sharedInstance];
//Set category of audio session
//See handy chart on pg. 46 of the Audio Session Programming Guide for what the categories mean
//Not absolutely required in this example, but good to get into the habit of doing
//See pg. 10 of Audio Session Programming Guide for "Why a Default Session Usually Isn't What You Want"
NSError *setCategoryError = nil;
if ([self.audioSession isOtherAudioPlaying])
{ //Mix sound effects with music already playing
[self.audioSession setCategory:AVAudioSessionCategorySoloAmbient error:&setCategoryError];
self.backgroundMusicPlaying = NO;
}
else
{
[self.audioSession setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
}
if (setCategoryError)
{
NSLog(#"Error setting category! %ld", (long)[setCategoryError code]);
}
}
-(void)configureAudioPlayer
{
//Create audio player with background music.
NSString *backgroundMusicPath = [[NSBundle mainBundle] pathForResource:#"ThemeA" ofType:#"mp3"];
NSURL *backgroundMusicURL = [NSURL fileURLWithPath:backgroundMusicPath];
self.backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:nil];
self.backgroundMusicPlayer.delegate = self; //We need this so we can restart after interruptions
self.backgroundMusicPlayer.numberOfLoops = -1; //Negative number means loop forever
}
#pragma mark - AVAudioPlayerDelegate methods
-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
//It is often not necessary to implement this method since by the time
//this method is called, the sound has already stopped. You don't need to
//stop it yourself.
//In this case the backgroundMusicPlaying flag could be used in any
//other portion of the code that needs to know if your music is playing.
self.backgroundMusicInterrupted = YES;
self.backgroundMusicPlaying = NO;
}
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flag
{
//Since this method is only called if music was previously interrupted, you know that the music has stopped playing & can now be resumed.
[self tryPlayMusic];
self.backgroundMusicInterrupted = NO;
}
#end
Here is the button code from OptionsScene:
#import "OptionsScene.h"
#import "ViewController.h"
BOOL soundON;
BOOL musicON;
#interface OptionsScene ()
#property (strong, nonatomic) AGSpriteButton *AGSoundButton;
#property (strong, nonatomic) AGSpriteButton *AGMusicButton;
#end
#implementation OptionsScene
{
NSUserDefaults *defaults;
}
-(id)initWithSize:(CGSize)size
{
self = [super initWithSize:size];
{
defaults = [NSUserDefaults standardUserDefaults];
[self background]; //Won't show code for this method since it just loads the background.
//Background music & sound dispatched once to get things going in this scene so to speak.
static dispatch_once_t onceOS;
dispatch_once(&onceOS, ^ {
//Code to run once
soundON = YES;
musicON = YES;
[defaults setBool:YES forKey:#"SoundButtonKEY"];
[defaults synchronize];
self.AGSoundButton.texture = [SKTexture textureWithImageNamed:#"checkboxYES"];
NSLog(#"SOUND switched to ON");
[defaults setBool:YES forKey:#"MusicButtonKEY"];
[defaults synchronize];
self.AGMusicButton.texture = [SKTexture textureWithImageNamed:#"checkboxYES"];
NSLog(#"MUSIC switched to ON");
});
}
return self;
}
-(void)update:(NSTimeInterval)currentTime
{
}
-(void)didMoveToView:(SKView *)view
{
//Sound button.
self.AGSoundButton = [AGSpriteButton buttonWithImageNamed:#"checkboxYES"];
self.AGSoundButton.position = CGPointMake(self.size.width/2 + 50, self.size.height/2 + 70);
self.AGSoundButton.zPosition = 2.2;
[self.AGSoundButton addTarget:self selector:#selector(soundInit) withObject:[NSValue valueWithCGPoint:CGPointMake(self.size.width + 230, self.size.height/2 + 3)] forControlEvent:AGButtonControlEventTouchUpInside];
[self addChild:self.AGSoundButton];
//Music button.
self.AGMusicButton = [AGSpriteButton buttonWithImageNamed:#"checkboxYES"];
self.AGMusicButton.position = CGPointMake(self.size.width/2 + 50, self.size.height/2 + 10);
self.AGMusicButton.zPosition = 2.2;
[self.AGMusicButton addTarget:self selector:#selector(musicInit) withObject:[NSValue valueWithCGPoint:CGPointMake(self.size.width + 230, self.size.height/2 + 3)] forControlEvent:AGButtonControlEventTouchUpInside];
[self addChild:self.AGMusicButton];
//Call upon the saved BOOL/Button positions from their respective key's.
BOOL soundDefaults = [defaults boolForKey:#"SoundButtonKEY"];
BOOL musicDefaults = [defaults boolForKey:#"MusicButtonKEY"];
//Sound button retrieval.
if (soundDefaults == YES)
{
self.AGSoundButton.texture = [SKTexture textureWithImageNamed:#"checkboxYES"];
NSLog(#"Sound is ON");
}
if (soundDefaults == NO)
{
self.AGSoundButton.texture = [SKTexture textureWithImageNamed:#"checkboxNO"];
NSLog(#"Sound is OFF");
}
//Music button retrieval.
if (musicDefaults == YES)
{
self.AGMusicButton.texture = [SKTexture textureWithImageNamed:#"checkboxYES"];
NSLog(#"Music is ON");
}
if (musicDefaults == NO)
{
self.AGMusicButton.texture = [SKTexture textureWithImageNamed:#"checkboxNO"];
NSLog(#"Music is OFF");
}
}
//Sound button switch ON/OFF.
-(void)soundInit
{
if (soundON == YES)
{
soundON = NO;
[defaults setBool:NO forKey:#"SoundButtonKEY"];
[defaults synchronize];
self.AGSoundButton.texture = [SKTexture textureWithImageNamed:#"checkboxNO"];
NSLog(#"SOUND switched to OFF");
}
else /*if (soundON == NO)*/
{
soundON = YES;
[defaults setBool:YES forKey:#"SoundButtonKEY"];
[defaults synchronize];
self.AGSoundButton.texture = [SKTexture textureWithImageNamed:#"checkboxYES"];
NSLog(#"SOUND switched to ON");
}
}
//Music button switch ON/OFF.
-(void)musicInit
{
if (musicON == YES)
{
musicON = NO;
[defaults setBool:NO forKey:#"MusicButtonKEY"];
[defaults synchronize];
self.AGMusicButton.texture = [SKTexture textureWithImageNamed:#"checkboxNO"];
NSLog(#"MUSIC switched to OFF");
}
else /*if (musicON == NO)*/
{
musicON = YES;
[defaults setBool:YES forKey:#"MusicButtonKEY"];
[defaults synchronize];
self.AGMusicButton.texture = [SKTexture textureWithImageNamed:#"checkboxYES"];
NSLog(#"MUSIC switched to ON");
}
}
//Brings back to GameScene. Called by a 3rd button that I didn't bother including in this code. It doesn't really matter.
-(void)backToGame
{
NSLog(#"Going back");
[defaults synchronize]; //Save button states, just in case, before leaving scene.
//Brings back to game scene.
MyScene *firstScene = [MyScene sceneWithSize:self.size];
[self.view presentScene:firstScene];
}
#end
Really hope this helps with the details.

Checkbox go to another view controller objective c

I am trying to create a checkbox button, when the user click on that button it will check in and take him to another view controller. below is my checkbox code, can anyone help how can send the user to the other view controller?
Note I am using a storybored.
The header
IBOutlet UIButton *Checkbox;
BOOL checked;
(IBAction)CheckboxAction:(id)sender;
and here is the code:
- (void)viewDidLoad : (BOOL)animated
{NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
checked = [defaults boolForKey:#"boxIsChecked"];
[self checkTheBox];}
-(void) checkTheBox
{
if (!checked)
{[Checkbox setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];}
else if (checked)
{[Checkbox setImage:[UIImage imageNamed:#"checkBoxMarked.png"] forState:UIControlStateNormal];}
}
- (IBAction)CheckboxAction:(id)sender
{NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (!checked)
{[Checkbox setImage:[UIImage imageNamed:#"checkBoxMarked.png"] forState:UIControlStateNormal];
checked = YES;
[defaults setBool:checked forKey:#"boxIsChecked"];}
else if (checked)
{[Checkbox setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
checked = NO;
[defaults setBool:checked forKey:#"boxIsChecked"];}
[defaults synchronize];
}
- (IBAction)CheckboxAction:(id)sender {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (!checked) {
[Checkbox setImage:[UIImage imageNamed:#"checkBoxMarked.png"] forState:UIControlStateNormal];
checked = YES;
[defaults setBool:checked forKey:#"boxIsChecked"];
}
else if (checked) {
[Checkbox setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
checked = NO;
[defaults setBool:checked forKey:#"boxIsChecked"];
}
[defaults synchronize];
// ADD THIS
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
YourViewController *yourVC = (YourViewController *)[storyboard instantiateViewControllerWithIdentifier:#"YourViewControllerIdentifier"];
[self.navigationController pushViewController:yourVC animated:YES];
}

NSUserDefaults not saving

I'm trying to save some data and call it back in a tableview from a different controller but it doesn't working. I'm somehow losing a variable value as well, like the category var changes back to zero when I change it in a view controller, any of them.
In my NewEntry.m I have:
-(IBAction)saveButton:(id)sender {
int i = selectedSegment.selectedSegmentIndex;
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setInteger:i forKey:#"category"];
[userDefaults synchronize];
if (selectedSegment.selectedSegmentIndex == 0) {
[userDefaults setObject:titlefield.text forKey:#"titletexthomework"];
[userDefaults setObject:detailstextfield.text forKey:#"detailshomework"];
}
else if(selectedSegment.selectedSegmentIndex == 1) {
[userDefaults setObject:titlefield.text forKey:#"titletextprojects"];
[userDefaults setObject:detailstextfield.text forKey:#"detailsprojects"];
}
else if (selectedSegment.selectedSegmentIndex == 2){
[userDefaults setObject:titlefield.text forKey:#"titletextappointments"];
[userDefaults setObject:detailstextfield.text forKey:#"detailsappointments"];
}
else if (selectedSegment.selectedSegmentIndex == 3){
[userDefaults setObject:titlefield.text forKey:#"titletextevents"];
[userDefaults setObject:detailstextfield.text forKey:#"detailsevents"];
}
else if (selectedSegment.selectedSegmentIndex == 4){
[userDefaults setObject:titlefield.text forKey:#"titletexttodolist"];
[userDefaults setObject:detailstextfield.text forKey:#"detailstodolist"];
}
[userDefaults synchronize];
NSLog(#"selected segment %i", i);
}
then in my Projects.m I have:
-(void)viewDidLoad
{
[super viewDidLoad];
categoryselected = [[NSUserDefaults standardUserDefaults] integerForKey:#"category"];
NSLog(#"category selected %i", categoryselected);
titlestring = [[NSUserDefaults standardUserDefaults] objectForKey:#"titletextprojects"];
detailsstring = [[NSUserDefaults standardUserDefaults] objectForKey:#"detailsprojects"];
tabledata = [[NSArray alloc] initWithObjects:titlestring, nil];
tablesubtitles = [[NSArray alloc] initWithObjects:detailsstring, nil];
}
//-------------------------------------------------------
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"projectscell"];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"projectscell"];
}
cell.textLabel.text = [tabledata objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [tablesubtitles objectAtIndex:indexPath.row];
cell.textLabel.font = [UIFont systemFontOfSize:14.0];
cell.textLabel.backgroundColor = [ UIColor clearColor ];
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
return cell;
}
*******UPDATE**************
I Changed the part that populates the table to static string like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
tabl = [[NSArray alloc] initWithObjects:#"hello", nil];
NSLog(#"tabledata %#", tabledata );
tab = [[NSArray alloc] initWithObjects:#"hello2", nil];
NSLog(#"details %#", tablesubtitles);
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"projectscell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"projectscell"];
}
cell.textLabel.text = [tabl objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [tab objectAtIndex:indexPath.row];
cell.textLabel.font = [UIFont systemFontOfSize:14.0];
cell.textLabel.backgroundColor = [ UIColor clearColor ];
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
And the table still shows up blank.
Thanks For the help.
Call synchronize AFTER setting any values.
I don't notice anything wrong in the NSUserDefaults code, per se, though it's only grabbing the values when the view loads, not when the values are updated. To fix that, you could send a notification to let all other interested view controllers aware of the state change. In -[NewEntry saveButton:], after saving the values in NSUserDefaults, add
[[NSNotificationCenter defaultCenter] postNotificationName:#"ValuesChanged"
object:self];
to send a notification. Somewhere in Projects.m (init is a good place), subscribe to the notification with
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(valuesChanged:)
name:#"ValuesChanged"
object:nil];
This causes the notification center to call back to your valuesChanged: method when the notification is posted. We'll be updating the UI in pretty much the same way we did in viewDidLoad, so let's factor that code out:
- (void)reloadData
{
categoryselected = [[NSUserDefaults standardUserDefaults] integerForKey:#"category"];
NSLog(#"category selected %i", categoryselected);
// XXX - note the following strings are returned autoreleased. If they're
// stored in ivars, it's a good idea to retain them, even though we know
// they're retained by the arrays below.
titlestring = [[NSUserDefaults standardUserDefaults] objectForKey:#"titletextprojects"];
detailsstring = [[NSUserDefaults standardUserDefaults] objectForKey:#"detailsprojects"];
[tabledata release];
tabledata = [[NSArray alloc] initWithObjects:titlestring, nil];
[tablesubtitles release];
tablesubtitles = [[NSArray alloc] initWithObjects:detailsstring, nil];
[tableView reloadData];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self reloadData];
}
- (void)valuesChanged:(NSNotification*)notification
{
[self reloadData];
}
One last thing: all those strings, the keys for NSUserDefaults and the notification name #"ValuesChanged"? They really should be defined as constants so that there's only one "true" version of the string. First, this saves you from the case where you accidentally misspell it in one place and wonder why the values aren't syncing up. It can take hours to figure out what's going on when that happens. (Speaking from experience here.) Second, the compiler can then check that you have the right name and the IDE's autocomplete (when it actually works) can suggest key names for you. You can do a #define in a shared header somewhere
#define kDefaultsKeySelectedCategory #"category"
and the linker will probably create a single constant instance of the string shared between every place it's used. Still, if I change the string in that define and Xcode's being cranky and doesn't recompile every source file that uses it, we're back to the case where the key is spelled differently in different places. No good. A fancier way to do this that ensures there's only one copy of the string is to declare
extern NSString* const kDefaultsKeySelectedCategory;
in the header file, then
NSString* const kDefaultsKeySelectedCategory = #"category";
in the .m file. Another thing I like about this way is it hides the implementation details. Nobody needs to know what the specific string is, so it shouldn't be in the header file.
I had the same issue when I was testing my app where if I use Stop in the debugger and then relaunch my app, the NSUserDefaults were incorrectly showing old list. This did not happen with the Insert operation, but with the Delete.
If I use the home button to exit the app (kill it), then relaunch, my NSUserDefaults were correct.
Alec Feb 23 '12 at 17:13 also mentioned this in an earlier comment.
I had an issue with NSUserDefaults not setting, even if you use the synchronize command right after. My issue was because the app was renamed and I believe that the NSUserDefaults didn't synchronize location correctly. I've uninstalled the app and reinstalled it from Xcode and it worked. I guess its a bit of a special case, but if anything try that.

viewDidLoad not running when expected

I have the following code in my viewDidLoad to change an image:
- (void)viewDidLoad
{
[super viewDidLoad];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"colour"] == nil) {
[defaults setObject:#"Red" forKey:#"colour"];
[defaults setInteger:0 forKey:#"colourIndex"];
[defaults synchronize];
}
[background setImage:[UIImage imageNamed:[defaults objectForKey:#"colour"]]];
NSLog(#"%#", [defaults objectForKey:#"colour"]);
// Logs "Blue"
}
When I open my flipside view in the iPhone Simulator and then go back to my original view, the result of the NSLog doesn't change and the image doesn't change. Why is this happening?
Move this code to viewWillAppear. viewDidLoad is not called every time the view is presented.
This link provides a good explanation.
UIViewController viewDidLoad vs. viewWillAppear: What is the proper division of labor?