AppDelegate int value keeps getting reset - objective-c

In my project AppDelegate file, I have an int declared called correctAnswersCountR1. So in the app they take a small quiz and that variable keeps track of how many correct answers they got. Now somewhere else in the project I use this variable like so:
int r1score=appDelegate.correctAnswersCountR1;
The problem is that apparently if I exit the app and come back, the value isn't remembered, and is set back to its default value. How can I store this number so that it is remembered if the user closes the app and comes back?

You can use NSUserDefaults to store your value:
**Saving**
//Do this right before the app exits
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// saving an NSInteger
[prefs setInteger:42 forKey:#"integerKey"];
// This is suggested to synch prefs, but is not needed
[prefs synchronize];
**Retrieving**
//Do this when your app is loaded again
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// getting an NSInteger
NSInteger myInt = [prefs integerForKey:#"integerKey"];

You could set up core data for your project, though unless you plan on storing more information persistently for your app Core Data might be a bit of overkill. You could also try writing it to a file and just reading it on load.
Edit: For this specific scenario Oscar's answer seems more appropriate, though depending on where you plan on going with your app, CoreData or a file may be a good choice.

You'll want to do some research about NSUserDefaults.
Here is the apple documentation
On another note it's not considered best practice to store data in the AppDelegate

You have to use a preferences storing mechanism. I'm not all too familiar with the iPhone toolkit, but on Mac OS X and Cocoa there's NSUserDefaults. When your app launches, you would load the value from the user defaults (preferences) through [[NSUserDefaults standardUserDefaults] intForKey:#"count"], and whenever the value changes, you would call [[NSUserDefaults standardUserDefaults] setInt:answerCount... forKey:#"count"].

I'm pretty sure that you want to write the value into a file to make it persistent.
This is because an application which moved to the background might be terminated for example if the system measures out that it needs some more memory.
So it kills the application and restarts it when the user switches over.

Related

NSUserDefaults won't delete object for key

When the user logs in to my application, I download a token from my JSON server and store it in NSUserDefaults, as such:
[[NSUserDefaults standardUserDefaults] setValue:token forKey:TOKEN];
When the user logs out in a subsequent page, I call this method and return back to the login screen:
[[NSUserDefaults standardUserDefaults] setObject:#"" forKey:TOKEN];
(and before that I called [[NSUserDefaults standardUserDefaults] removeObjectForKey:TOKEN];)
It doesn't matter how I try to delete this user defaults, whenever I load up my app, it always shows me the full token and not an empty string nor a null value.
When reading around, apparently it has something to do with read write cycles? But even if i leave it for a while, the key still remains. Is this a simulator problem?
Whatever the cause, how do i get around this?
It's the simulator problem of caching the memory first. It only happens in xcode and should not happen on a device.
Do you call
[[NSUserDefaults standardUserDefaults] synchronize];
after the key was deleted? Maybe you are not persisting the changes into the database.

Xcode: Saving an Int value [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I have a simple counter application, i.e. the user presses a button to increase it by a value of their choice. I started the application production on a single view application. I now have the need to make it so that when the app is closed it saves the last value of the counter. Then when the app reopens it needs to load the value of the counter back into place. The value needs to be saved and reloaded simply by closing and opening the app i.e. no buttons are needed to be pressed.
My counter variable is an Int value called counter. The view controllers are simply named viewController.h/m.
I have no idea how to set all of this up, I assume I need coreData to do this. How do I set up coreData? Do I code in my delegate of viewController? If this is not the best way to do it please provide a way to do it in a more effective way!
Thanks very much for any help, simple instructions appreciated most of all.
I have had a look at other example of this but none seemed to provide what I need or were simple enough to understand. Please provide an answer on this thread!
Hugh
It's easiest to simply use NSUserDefaults instead of Core Data.
To save:
[[NSUserDefaults standardUserDefaults] setInteger:counter forKey:#"counter"]
To read:
NSInteger counter = [[NSUserDefaults standardUserDefaults] integerForKey:#"counter"];
Take a look at UIApplicationDelegate to find what methods you should place the code in. It will likely be in your AppDelegate in one of the following methods:
Where to load the value:
-application:didFinishLaunchingWithOptions:
–applicationWillEnterForeground:
Where to save the value:
-applicationDidEnterBackground:
–applicationWillTerminate:
Exactly where depends on if you need to load and save the value when the user switches to another app, which is almost certainly the case as the app might be terminated when it is in a frozen state due to memory pressure. In this case you would want to make sure the value was saved when the app was backgrounded (the user switched to a different app) and the value was restored when the app became the foreground app (the user switched back to your app).
You can use NSUserDefaults.
You can store a variable creating an NSUserDefaults variable with
NSUserDefaults * standardUserDefaults = [NSUserDefaults standardUserDefaults];
Then save the integer with
[standardUserDefaults setInteger:1 forKey:#"integer"];
And synchronize all with [standardUserDefaults synchronize];
Then retrieve the integer creating a variable:
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
and then recover it with
NSInteger myInt = [standardUserDefaults integerForKey:#"integer"];

How to force localization at compileTime or better at runtime

i've got a IOS project with many different images to display depending on the language, and i can't find a way to force loading the correct image at runtime (not switching a language to another).
Actually it seems that the files are loaded before the AppDelegate get a chance to interfer.
if i do in appDelegate (didFinishLaunchingWithOptions:):
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects: #"es", #"en", nil] forKey:#"AppleLanguages"];
It's already too late, image are already loaded in the wrong language. So in order to accomplish this i have moved the NSUserDefaults into the main() call, and this tricks works. But my questions are: Do Apple will reject my app? And is there a better, clean approach to synchronize a language at compile time (or with plist or something like that)?
Update
it seems that just replacing [[NSUserDefaults standardUserDefaults] setObject: forKey:], further step before calling my nib file did the trick. It's like [NSUserDefaults standardUserDefaults] is called asynchronously. So maybe the setter method was actually evaluated after my nib file was loaded. But can i change the localizable setting via info.plist ?
You can localize the Info.plist (InfoPlist.strings), which lets you set the Default.png for each language.

iOS settings toggle switch works the first time but not again

I am using the iPad settings app to change some button sounds and a background image. It all works well and the settings are maintained from one app launch to another in the simulator. Now I have implemented a toggle switch to either set sets of sounds off or on. When the app launches, whatever state the switch is in, it works; e.g. if the "Alert Sounds" switch is OFF the alert sounds are silent and if I change it to ON the sounds will start working. However, if I turn the switch back OFF the sounds still keep working. However, if the state is ON when the app launches, the sounds work, but will not be silenced when the switch is set to OFF.
Note that this is different than the settings not taking effect until a second round of settings. That was a previous problem I solved (thanks to stack overflow) by using:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[NSUserDefaults standardUserDefaults] synchronize];
}
I have methods named:
- (void)defaultsChanged:(NSNotification *)NSUserDefaultsDidChangeNotification
(which is called when the notification is sent)
and
-(void)setValuesFromPreferences
(which is called in ViewDidLoad)
The logic looks like this in both:
// Set alert sounds from preferences
NSString *alertSoundPreference = [userDefaults stringForKey:kAlertSound];
BOOL alertSoundEnabled = [userDefaults boolForKey:kAlertSoundEnabled];
if (alertSoundEnabled)
{
// Create the URLs for the alert audio files
// Store the alert sound URLs as a CFURLRef instances
// Create system sound objects representing the alert sound files
}
I do not have an else, because I assume that no sound resources will be specified if alertSoundEnabled is NO.
I have searched for explanations and tutorials that mention this problem but have not found any yet, so I'm asking here. Thanks for any suggestions.
viewDidLoad is not necessarily called when the app becomes active again (nor does viewWill/DidAppear, IIRC), as the whole point of iOS 4+ multitasking is to prevent such loading/unloading and recreation of objects on app-switching.
If I had to guess, the sounds are already allocated when the user had the switch ON at original launch/viewDidLoad; however, if your code does nothing to explicitly disassociate them when it loads back up, they would continue playing, as they are all already set up.
As such, I'd try adding an else clause that (upon alertSoundEnabled == NO) destroys your system sound objects.

Using iPodMusicPlayer without giving control to iPod in background

I'm developing an app with a very specific focus on shuffling songs within a selected playlist. When the app launches, it lists all the user's playlists, and then when one is selected it loads it into my music player view and get's going. I'm using an MPMusicPlayerController iPodMusicPlayer to handle doing this because I'm pretty new at iOS development and it handles backgrounding and everything nice and easily for me. I want music to continue playing in the background and I like how whatever I change within my app is also reflected in the iPod app. However, I don't want the user to be able to change things in the iPod app and then return to mine. Since my app is all about shuffling, the user could easily go into iPod and disable shuffle, then come back to my app and the experience is ruined. I also don't want them to change the playlist from within iPod.
Can anyone help me think of a way to accomplish this? Play/pause/skip/prev/volume is no problem from within iPod (I want that to be possible), but I don't want changing the song queue to be possible. Is there a way I could add a handler in my app that catches if the user changed something while my app was in the background (and if so, stop music and reset my app to the initial screen)? I'd really appreciate any suggestions. I'm hoping something like this is possible before I venture into using AVPlayerQueue or the like (as a side note, can you play DRM'd files with AVPlayerQueue?).
What I would do is set a bool when backgrounded:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setBool:YES forKey:#"BACKGROUNDED"];
Then, in your handler for the MPMusicPlayerControllerNowPlayingItemDidChangeNotification that you should be implementing so that you have that control, do the following:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
if ([prefs boolForKey:#"BACKGROUNDED"]) {
[prefs setBool:NO forKey:#"BACKGROUNDED"];
exit(0);
}
It might be too abrupt, depending on when it checks this code (I don't know when it does in your project) but that should accomplish your goal. exit(0) is the way to terminate your app without throwing an exception. Is that helpful?