I have a Scenario , where i have to call a Method only once , whenever a User Will Update the Application or make a Fresh Install.
SO my Question is there is any particular Method to be called in App Delegate , After We update the Application , so if someone can tell me a another way to Achieve this , that would be really appreciated.
I would set a value in NSUserDefaults after you have called the function one time. See the accepted answer here: iOS : Call a method just one time
If you need to run after an update, you should include an always increasing number, or pull the build number, and check against the saved value. This will allow you to know if the app has been updated.
I am writing following function which uniquely checks if user has rated the current version, [self nowRate] is the function, please change this to whatever action you want to perform uniquely per version
-(void)rateApp {
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
NSMutableDictionary*appRatedForVersion = [[NSMutableDictionary alloc] init];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([[[NSUserDefaults standardUserDefaults] dictionaryRepresentation].allKeys containsObject:#"AppRateDictionaryData"]){
NSData *versionRateData = [defaults objectForKey:#"AppRateDictionaryData"];
appRatedForVersion = [NSKeyedUnarchiver unarchiveObjectWithData:versionRateData];
if ([appRatedForVersion objectForKey:version] != nil) {
NSNumber *isAppRatedForCurrentVersion = [appRatedForVersion objectForKey:version];
BOOL hasBeenRated = [isAppRatedForCurrentVersion boolValue];
if (hasBeenRated) {
//Action already performed in this version do whatever you like
} else {
[self nowRate];
}
} else {
[appRatedForVersion setObject:[NSNumber numberWithBool:YES] forKey:version];
NSData *versionRateData1 = [NSKeyedArchiver archivedDataWithRootObject:appRatedForVersion];
[defaults setObject:versionRateData1 forKey:#"AppRateDictionaryData"];
[defaults synchronize];
[self nowRate];
}
} else {
[appRatedForVersion setObject:[NSNumber numberWithBool:YES] forKey:version];
NSData *versionRateData = [NSKeyedArchiver archivedDataWithRootObject:appRatedForVersion];
[defaults setObject:versionRateData forKey:#"AppRateDictionaryData"];
[defaults synchronize];
[self nowRate];
}
}
Related
I was using xCode 3.2 and then moved to xCode 4.2 and getting some values from Settings.bundle ... it was working fine.
Mean while I need to edit some values in Settings.bundle but The Root.plist file was not showing so I follow the below procedure but did not make any change in file.
1) Click on the Settings.Bundle file, go over to the utilities window,
and look in the File Inspector.
2) Using the drop-down, change the file type to 'Application Bundle'
After that I could see Root.plist but now could not get its values in application. Actually getting Null instead of value.
Below is code and image of Settings.bundle
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
host = [defaults stringForKey:#"meter_preference"];
if(host == nil)
{
host = #"10.20.20.1";
DDLogError(#"Meter host is nil from NSUserDefaults, defaulting to %#", host);
}
I got the solution, just call the below code in applicationDidFinishLaunchingWithOptions to initialize User defaults. and it works
Replace somePropertyYouExpect in first line with property you stored in User Defaults.
if (![[NSUserDefaults standardUserDefaults] objectForKey:#"somePropertyYouExpect"]) {
NSString *mainBundlePath = [[NSBundle mainBundle] bundlePath];
NSString *settingsPropertyListPath = [mainBundlePath
stringByAppendingPathComponent:#"Settings.bundle/Root.plist"];
NSDictionary *settingsPropertyList = [NSDictionary
dictionaryWithContentsOfFile:settingsPropertyListPath];
NSMutableArray *preferenceArray = [settingsPropertyList objectForKey:#"PreferenceSpecifiers"];
NSMutableDictionary *registerableDictionary = [NSMutableDictionary dictionary];
for (int i = 0; i < [preferenceArray count]; i++) {
NSString *key = [[preferenceArray objectAtIndex:i] objectForKey:#"Key"];
if (key) {
id value = [[preferenceArray objectAtIndex:i] objectForKey:#"DefaultValue"];
[registerableDictionary setObject:value forKey:key];
}
}
[[NSUserDefaults standardUserDefaults] registerDefaults:registerableDictionary];
[[NSUserDefaults standardUserDefaults] synchronize];
}
From your code , try this thinks..
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
host = [defaults stringForKey:#"meter_preference"];
if(!host == nil)
{
host = #"10.20.20.1";
DDLogError(#"Meter host is nil from NSUserDefaults, defaulting to %#", host);
}
OR
Review this link may be helped you...
iPhone - reading Setting.bundle returns wrong values
NSUserDefaults Settings Bundle Plist
I developed a small game , , so I manage something like this , when app lunches for the first time , it save the very first record , then after that it loads and compares the new records with the the first time record . but the problem is when user hit the record it should be saved the new record but it doesn't !!! and saves the first record again ! here is my code :
- (void)manageScores {
NSLog(#"managed");
NSString *tempScore = [NSString stringWithFormat:#"%#",scoreLabel.text];
GO.scoreNumber = [tempScore integerValue];
GO.bestScoreNumber = [tempScore integerValue];
GO.scores.text = [NSString stringWithFormat:#"score:%d",GO.scoreNumber];
GO.bestScore.text = [NSString stringWithFormat:#"best:%d",GO.bestScoreNumber];
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"])
{
// app already launched
NSLog(#"app already launched");
[GO loadBestScore];
}
else
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"HasLaunchedOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
// This is the first launch ever
NSLog(#"first time lunch ever");
[GO saveBestScore];
}
if (GO.scoreNumber > GO.bestScoreNumber) {
//**************THIS METHOD DOESN'T WORK WHEN USER HIT THE RECORD*********/////
[GO saveBestScore];
//**************//
GO.scores.text = [NSString stringWithFormat:#"score:%d",GO.scoreNumber];
GO.bestScore.text = [NSString stringWithFormat:#"best:%d",GO.scoreNumber];
GO.shareScore.text = [NSString stringWithFormat:#"score:%d",GO.bestScoreNumber];
NSLog(#"new record");
}
if (GO.scoreNumber < GO.bestScoreNumber) {
GO.scores.text = [NSString stringWithFormat:#"score:%d",GO.scoreNumber];
GO.bestScore.text = [NSString stringWithFormat:#"best:%d",GO.bestScoreNumber];
GO.shareScore.text = [NSString stringWithFormat:#"score:%d",GO.bestScoreNumber];
[GO loadBestScore];
NSLog(#"NO NEW RECORD");
}
}
saving and loading scores (methods form GameOver.h/m (GO) )
- (void)saveBestScore {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setInteger:bestScoreNumber forKey:#"highScore"];
[defaults synchronize];
NSLog(#"BEST SCORE SAVED:%i",bestScoreNumber);
}
- (void)loadBestScore {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
bestScoreNumber = (int)[prefs integerForKey:#"highScore"];
}
Looks like you should save scoreNumber rather than bestScoreNumber
Reason:
The following code wants to save the best score because GO.ScoreNumber > Go.BestScoreNumber.
if (GO.scoreNumber > GO.bestScoreNumber) {
//**************THIS METHOD DOESN'T WORK WHEN USER HIT THE RECORD*********/////
[GO saveBestScore];
//**************//
GO.scores.text = [NSString stringWithFormat:#"score:%d",GO.scoreNumber];
GO.bestScore.text = [NSString stringWithFormat:#"best:%d",GO.scoreNumber];
GO.shareScore.text = [NSString stringWithFormat:#"score:%d",GO.bestScoreNumber];
NSLog(#"new record");
}
But in saveBestScore, it stores bestScoreNumber, which is the previous highest score number.
[defaults setInteger:bestScoreNumber forKey:#"highScore"];
- (void)saveBestScore
This method doesn't take an argument, but it should.
If you're keeping scores as int, you should modify it to look like this:
- (void)saveBestScore:(int)bestScore
Then, on first launch, call saveBestScore with an argument of 0, just to get it initialize. In fact, if you write saveBestScore method correctly, you don't really need to check whether the app has already launched ever.
- (void)saveBestScore:(int)bestScore {
if (bestScore > [[[NSUserDefaults standardUserDefaults]
objectForKey:#"BestScore"] intValue]); {
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber
numberWithInt:bestScore] forKey:#"BestScore"];
}
- (int)loadBestScore {
return [[[NSUserDefaults standardUserDefaults] objectForKey:#"BestScore]
intValue];
}
I want to save some user preferences, but
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
just returns nil.
iOS-Developper Library says, that this should return the existing shared defaults object or create one if none exists... What am I missing?
I also use Appirater and there all this stuff seems also not to work...
This code gets called when the user pushes a button...
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
int index = ([defaults integerForKey:#"BackgroundColorSpecifier"]+ 1)%self.backgroundColors.count;
[defaults setInteger:index forKey:#"BackgroundColorSpecifier"];
[defaults synchronize];
This gets called in application: didFinishLaunchingWithOptions:
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
[standardDefaults registerDefaults:#{#"BackgroundColorSpecifier": #0}];
[standardDefaults synchronize];
When I debug this code snippets the green "position-indicator" jumps around in a very strange manner...
I don't have any clue, whats going on... Please help!
This is far more likely to be a problem with the debugger than anything else, particularly with your other issues. I've seen similar things in my own projects but don't have a reliable way of clearing it out other than the usual restart / clean options.
NSLogs will usually give more consistent results than the debugger if the debugger is having an off day.
NSUserDefaults isn't broken. We'd have heard about it by now.
you can use this function to log you userDefaults dic
- (void)logCache
{
NSDictionary * dic = [[NSBundle mainBundle] infoDictionary];
NSString *bundleId = [dic objectForKey: #"CFBundleIdentifier"];
NSUserDefaults *appUserDefaults = [[NSUserDefaults alloc] init];
NSDictionary *cacheDic = [appUserDefaults persistentDomainForName: bundleId];
NsLog(#"cacheDic::%#",cacheDic);
}
I am making a game in Xcode which in includes a scoring system in each level. Here I have some code that gets an NSString (passedValue1) by using a delegate.
Then i add the code to receive the value in my viewDidLoad and display my value in a UILabel
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib
// Do any additional setup after loading the view, typically from a nib
NSString *key=#"labelKey";
if(passedValue1){
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSObject * object = [prefs valueForKey:key];
if(object != nil){
NSUserDefaults *defults = [NSUserDefaults standardUserDefaults];
[defults setValue:passedValue1 forKey:key];
[defults synchronize];
}
else{
NSUserDefaults *defults = [NSUserDefaults standardUserDefaults];
NSInteger readScore=[[[NSUserDefaults standardUserDefaults] valueForKey:key] integerValue];
NSInteger newValue=readScore+[passedValue1 integerValue];
[defults setValue:[NSString stringWithFormat:#"%d",newValue] forKey:key];
[defults synchronize];
}
}
label.text = [[NSUserDefaults standardUserDefaults]objectForKey:key];
}
Once I have displayed the value I then save it into a label using a NSUserDefault. However, once I have replayed my game and have another score value I would like to add the new passedValue1 value to the currently saved value...
For example:
say I play my level and I get the score value of 10. The value is then saved and I replay my level. I would then like to take the saved value and add it to the value i just scored. So thats say the second value I have scored is 20. I would then like my code to add them together and give me a value of 30.
can anyone help because the code I'm using does not correctly do the function that I want to do which is add the previous and the currently passed value.
What is wrong with my code??
Thanks in advance.
You shouldn't use valueForKey: for this (it's not what you might think it is, see Key-Value Coding). Instead, you should use objectForKey: or in your case integerForKey:.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger value = [defaults integerForKey:key];
value += [passedValue1 integerValue];
[defaults setInteger:value forKey:key];
BOOL success = [defaults synchronize];
It seems that you got your if condition wrong, it should be
if (object == nil) { // <-- you have object != nil here !
// save new value
} else {
// read old value, add something, save new value
}
How to know whether NSUserDefaults contains any value?How to check whether its empty?
There isn't a way to check whether an object within NSUserDefaults is empty or not.
However, you can check whether a value for particular key is nil or not.
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSObject * object = [prefs objectForKey:#"your_particular_key"];
if(object != nil){
//object is there
}
NSUserDefaults *data = [NSUserDefaults standardUserDefaults];
NSString *string = [data objectForKey:#"yourKey"];
if(string==nil)
NSlog(#"nil")
Take a look at NSUserDefault documentation
// For saving the values
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
// saving an NSString
[userDefaults setObject:#"Ttest" forKey:#"key"];
// --- For Retrieving
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
// getting an NSString
NSString *myString = [userDefaults stringForKey:#"key"];
To check whether a specific value is set or not, no matter of its location (global or application's), check the returned value of -[NSUserDefaults objectForKey:]
id obj = [[NSUserDefaults standardUserDefaults] objectForKey:#"My-Key-Name"];
if (obj != nil) {...}
To check if the application (bundle) has any settings stored in user defaults:
NSUserDefaults* sdu = [NSUserDefaults standardUserDefaults];
NSString* bundleId = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary* mainBundleSettings = [sdu persistentDomainForName:bundleId];
NSLog(#"%#", mainBundleSettings);
If you are interested in all possible values for which -[NSUserDefaults objectForKey:] will return something, including system global settings, simply call
NSDictionary* allPossibleSettings = [sdu dictionaryRepresentation];
NSUserDefaults is never empty. It combines global settings, bundle's settings, temporary data and maybe something else. For example, if you call:
[[NSUserDefaults standardUserDefaults] objectForKey:#"NSBoldSystemFont"]
you will get the #"LucidaGrande-Bold" string value which will be taken from global settings, even when your application has never set this value.