Programatically change the Fn key behavoiur Mac OS X - objective-c

I want to write a simple cmdline app that will toggle the "Use all F1,F2... keys as standard function keys". I know i can use appleScript, but that shows the gui and is not nice. So how to do that from code? I tried the defaults command defaults write -g com.apple.keyboard.fnState -bool false and that does change the preferences flag when read with defaults command but not in the GUI and it is not working.
Also tried something like that:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *key = #"com.apple.keyboard.fnState";
BOOL fnState = [defaults boolForKey:key];
NSLog(#"First value of fnState: %#", fnState ? #"true" : #"false" );
if (fnState) {
[defaults setBool:NO forKey:key];
}
else{
[defaults setBool:YES forKey:key];
}
fnState = [defaults boolForKey:key];
NSLog(#"Value of fnState after toggle: %#", fnState ? #"true" : #"false" );
[NSUserDefaults resetStandardUserDefaults];
This one has proper states logged between runs, but defaults command does not see it, and the Fn key does not care either.
How should one proceed ? I know it can be done.

Related

How to load the user’s last selected value for a slider when the app relaunches?

I am new to Xcode and I am using Objective C in OSX.
I am trying to load the user’s last selected value for a slider when the app relaunches.
my code for the slider is…
- (IBAction)sliderChanged:(id)sender {
amount = [self.amountSlider integerValue];
NSString *amountString = [NSString stringWithFormat:#"%ld", amount];
[self.amountLabel setStringValue:amountString];
}
I have this setter…
- (void)setInteger:(NSInteger)valueforKey:(NSString *)defaultName{
[[NSUserDefaults standardUserDefaults] setObject:#"amountString" forKey:#"amountSlider"];
}
I would like to know how to code the getter.
A step-by-step instructions with code will be appreciated.
Any improvements/corrections to my existing code above would also be appreciated.
Make separate functions for retrieving, saving from defaults like this.
- (void)saveValueToUserDefaults:(NSString *)pValue key:(NSString *)kKey {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[self removeValueFromUserDefaults:kKey];
[defaults setObject:pValue forKey:kKey];
[defaults synchronize];
}
- (void)removeValueFromUserDefaults:(NSString *)kKey {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:kKey]) {
[defaults removeObjectForKey:kKey];
}
}
- (NSString *)retriveValueFromUserDefaults:(NSString *)kKey {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:kKey]) {
return [defaults objectForKey:kKey];
} else {
return kStringEmpty;
}
}
This will make simple to save and retrieve values from defaults.
Like-
[self saveValueToUserDefaults:YOUR_AMOUNT forKey:YOUR_KEY];
and get like this,
YOUR_AMOUNT = [self retriveValueFromUserDefaults:YOUR_KEY];
You asked for it :D
in your class create integer variable called amountChecker = 0
create a function called checker like this :
-(void) checker {
if (amount == amountChecker){
[[NSUserDefaults standardUserDefaults] setObject:amountLabel.text forKey:#"amountSlider"];
}
else
amount = amountChecker;
}
then .. in this function :
- (IBAction)sliderChanged:(id)sender {
amount = [self.amountSlider integerValue];
NSString *amountString = [NSString stringWithFormat:#"%ld", amount];
[self.amountLabel setStringValue:amountString];
[self performSelector:#selector(checker) withObject:nil afterDelay:1];
}
now this code will only store your value if a second passes and your slider didn't change , instead of storing your value like 60 times every second :D
it all starts when you change the slider then after one second it will check if the value changed if not it will store it
and when you reopen the app you will use this code :
amount = [[NSUserDefaults standardUserDefaults] objectForKey:#"amountSlider"];

NSUserDefaults Reset First Run

I have an app already in the AppStore that uses NSUserDefaults. Some of the defaults are Default settings that I go ahead and set when the app is first launched, and then the user is allowed to change them later if they wish. So, in my AppDelegate appDidFinishLaunchingWithOptions I put:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (! [defaults boolForKey:#"notFirstRun"]) {
[defaults setBool:YES forKey:#"notFirstRun"];
[defaults setInteger:0 forKey:#"verseKey"];
[defaults synchronize];
}
The issue I am having now is I want to add some more Default settings in the NSUserDefault category, so I want to make it look like this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (! [defaults boolForKey:#"notFirstRun"]) {
[defaults setBool:YES forKey:#"notFirstRun"];
NSString *smalltitle = #"4";
NSString *smallarticle = #"3";
[defaults setObject:smalltitle forKey:#"Title"];
[defaults setObject:smallarticle forKey:#"Article"];
[defaults setInteger:0 forKey:#"verseKey"];
[defaults synchronize];
}
I know that this will cause an issue for those who have already downloaded the app, and are merely updating it. They will not run that code because the notFirstRun Bool has already been set to YES. Any thoughts on what I should do here?
The proper solution is to not actually populate NSUserDefaults with default values. Instead, use the registerDefaults: method.
At app startup you do:
NSUserDefaults *default = [NSUserDefaults standardUserDefaults];
[defaults registerDefaults:#{
#"Title" : #"4",
#"Article" : #"3",
#"verseKey" : #0
}];
That's it. Call this every time the app is run. These defaults are not actually persisted. The value is only returned if there isn't already an explicit value for the key. You can update these defaults all you want without affecting any existing values.
Make a new notFirstRun Boolean value (i.e. notFirstRunTwo). That will be 'NO' for existing users, too.
I suggest to do the following :
check userdefaults for stored app version if it is equal to the current or not , if not.
store the current app version and do your first launch initialization
the code
`
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *appVersion = [NSString stringWithFormat:#"%#",[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleShortVersionString"]];
if (! [defaults objectForKey:appVersion ])
{
/// store the current version and then do your first run functions
[defaults setObject:[NSNumber numberWithInt:1] forKey:appVersion];
/// here do your first run
......
}`

Checking if view controller has been loaded before

I am trying to checking if a certain view has been loaded ever before in the lifetime of the app. I have implemented the following code but not quite sure why it isn't working. It is being done in the viewDidLoad method only of the view controller (perhaps this is the problem). If anyone can let me know what my mistake is, it would be appreciated. Thanks!
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL hasRunBefore = [defaults boolForKey:#"FirstRun"];
if (hasRunBefore) {
NSLog (#"not the very first time this controller has been loaded");
[defaults setBool:YES forKey:#"FirstRun"];
[defaults synchronize];
}
else if (!hasRunBefore) {
[defaults setBool:NO forKey:#"FirstRun"];
NSLog (#"the very first time this controller has been loaded");
[defaults synchronize];
}
There are a couple of mistakes in your code. See the corrections below:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL hasRunBefore = [defaults boolForKey:#"FirstRun"];
if (hasRunBefore) {
NSLog (#"not the very first time this controller has been loaded");
/* Toggle the boolean state */
[defaults setBool:NO forKey:#"FirstRun"];
}
else if (!hasRunBefore) {
/* Toggle the boolean state */
[defaults setBool:YES forKey:#"FirstRun"];
NSLog (#"the very first time this controller has been loaded");
}
[defaults synchronize];
However, I am not sure why you would want to toggle the FirstRun back to NO in the if(hasRunBefore). I only point out what is wrong, you might want to check your logic again.
-EDIT-
Like I pointed out about your logic, you should only have this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL hasRunBefore = [defaults boolForKey:#"FirstRun"];
if (!hasRunBefore) {
[defaults setBool:YES forKey:#"FirstRun"];
[defaults synchronize];
NSLog (#"the very first time this controller has been loaded");
}
else
NSLog (#"Not the first time this controller has been loaded");
The values set in defaults are persistent for as long as the app is installed on the device.
You should think about using a BOOL value set in the app delegate (which does not persist from run to run)
OR
You should set "FirstRun" back to NO in your app delegate in the following method.
- (void)applicationWillTerminate:(UIApplication *)application
NSUserDefaults is a possibility, but you could also use a static BOOL and set it to YES when the view controller is loaded for the first time.

Cocoa Preferences Overwritten

I have a couple questions regarding application preferences using NSUserDefaults.
In my last app I would link my preferences using bindings to NSUserDefaults, and this worked perfectly. In the application startup methods I could then perform actions based on the values stored in the NSUserDefaults.
The problem occured when I updated my application and re-distributed it, in which all the settings would get over-written with the preferences in my computer. So if someone changed the settings, and then received the update, their settings would get over-written with mine.
Looking back at the Apple documentation in regards to saving Preferences, I notice the following line which I didn't use, which is used to write preferences to disk:
[defaults synchronize];
My question is, does this code write the preferences to the user's harddrive, so that if I re-distribute the application with different settings, NSUserDefaults will read from the disk instead?
Sorry for the misunderstanding but I can't find an answer.
Thanks in advance everyone.
If you want to use bindings to control your preferences, you should be using NSUserDefaultsController. In either case, to set initial values for your defaults, you should create a dictionary with the initial values and then pass it to registerDefaults: if you're using vanilla NSUserDefaults, or one of initWithDefaults:initialValues: or setInitialValues: if you're using NSUserDefaultsController. Here's an NSUserDefaultsExample:
- (void)applicationDidFinishLaunching {
// For decent-sized applications, I normally like to store this in its own plist
// but I'm creating it in-line here for readability's sake.
NSDictionary *initialPreferences = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInteger:21], #"UserAge",
#"red", #"FavoriteColor",
#"Idaho", "Location", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:initialPreferences];
}
NSUserDefaults are only written when synchronize is called.
When you ship your app and you want specific settings in place at first launch, you need to set these yourself in code. I usually look for a nil value for a specific key and if it an empty value, I will set the desired "default" value.
Example
I do this when the application launches:
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
/* count how many times the user has launched the app */
int total = [[defaults objectForKey:#"kLaunchCount"] intValue]; total++;
[defaults setObject:[NSNumber numberWithInt:total] forKey:#"kLaunchCount"];
/* User chose to reset Scanner Feed, remove the .plist from Documents directory. */
if ( [[defaults objectForKey:#"kResetScannerFeeds"] boolValue] == YES ){
[[NSFileManager defaultManager] removeItemAtPath:SCANNERFEED error:nil];
[defaults setObject:[NSNumber numberWithBool:NO] forKey:#"kResetScannerFeeds"];
}
/* Check to see if Default Prefs are NULL, if so, enable them. */
if ( [defaults objectForKey:#"kShakeToToggleVisibility"] == nil ){
[defaults setObject:[NSNumber numberWithBool:YES] forKey:#"kShakeToToggleVisibility"];
}
if ( [defaults objectForKey:#"kBackgroundAudio"] == nil ){
[defaults setObject:[NSNumber numberWithBool:YES] forKey:#"kBackgroundAudio"];
}
if ( [defaults objectForKey:#"kUseMyLocation"] == nil ){
[defaults setObject:[NSNumber numberWithBool:YES] forKey:#"kUseMyLocation"];
}
if ( [defaults objectForKey:#"kAttachTwitterIcon"] == nil ){
[defaults setObject:[NSNumber numberWithBool:YES] forKey:#"kAttachTwitterIcon"];
}
if ( [defaults objectForKey:#"kAttachTwitterLink"] == nil ){
[defaults setObject:[NSNumber numberWithBool:YES] forKey:#"kAttachTwitterLink"];
}
/* User chose to log out of Facebook Session, do that now. */
if ( [[defaults objectForKey:#"kLogoutFacebook"] boolValue] == YES ){
[defaults setObject:[NSNumber numberWithBool:NO] forKey:#"kLogoutFacebook"];
[self fbLogout];
}
[defaults synchronize];

save bool in nsuserdefaults

when my app starts music is playing:
-(void)playBgMusic {
NSString *path = [[NSBundle mainBundle] pathForResource:#"bgmusic" ofType:#"aif"];
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play]; }
but he should be able to turn the music off by pressing a button if he presses the button again the music should turn on again. i have:
-(IBAction)check {
if (isquiet == NO) {
[theAudio stop];
isquiet = YES;
defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:YES forKey:#"stringKey"];
}
else {
[self playBgMusic];
isquiet = NO;
defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:NO forKey:#"stringKey"]; } }
I think I didn't get it. Now it works in my first ViewController that I can turn the music on and off but when I go to another viewController while the music is playing, then back again and press the button, the music doesn't stop and when i press it many times the music is played a second time and overlaps.
What's still wrong?
No need to wrap it in an NSNumber, there are some convenience methods for this:
To set a BOOL, use:
[userDefaults setBool:YESorNO forKey:#"yourKey"];
To access it, use:
[userDefaults boolForKey:#"yourKey"];
[EDIT TO ANSWER YOUR ADDITIONAL QUESTION]
Not sure why you are using NSUserDefaults - it seems unnecessary for what you are trying to achieve? Here's what I would do for a button that can start/stop music:
-(IBAction)check
{
if (isQuiet)
{
// Play music
// Change the button to indicate it is playing...
} else
{
// Stop music
// Change the button to indicate it has stopped...
}
// Set your isQuiet to be the opposite of what it was when the button was clicked
isQuiet = !isQuiet;
}
Box your BOOL value to NSNumber object and add it to NSUserDefault:
NSUserDefaults *boolUserDefaults = [NSUserDefaults standardUserDefaults];
[boolUserDefaults setObject:[NSNumber numberWithBool:isquiet]
forKey:#"stringKey"];
Later you'll be able to retrieve that value as plain BOOL using -boolForKey: function in NSUserDefaults
To save:
[boolUserDefaults setObject:[NSNUmber numberWithBool:isQuiet] forKey:#"stringKey"];
When you read it back, read it as a NSNumber then do:
BOOL savedIsQuiet = [theNumberYouSaved boolValue];
Swift:
To save bool:
UserDefaults.standard.set(true, forKey: "storageKey")
To retrieve the bool:
let boolValue = UserDefaults.standard.bool(forKey: "storageKey")