NSUserDefauts - Only new NSStrings not appearing in app - ios

Before explaining the issue, I want to mention I have already tried solutions from these questions:
Xcode not building app with changes incorporated
Why can't I delete files from my XCode project?
XCode simulator is not displaying latest changes
I have archived my app and it is now submitted in the App Store, but now I cannot make the changes I need in order to provide sound updates. The app provides statistics for different topics, as well as MLA/APA citations and a web view of that source. The code is structured this way:
A TopicViewController.m holds NSString variables for each statistic, citation, and source URL. IBActions related to specific topic UIButtons, like Cybersecurity for example, set the content of each NSString variable. Finally, I save the data for all stats, citations and URLs in NSUserDefaults and synchronize them. THESE IBACTIONS ARE WHERE I ADD NEW CONTENT.
sample code (the actual number of strings is very very large):
#implementation StatsViewController
NSString *cybersecStatistic1;
NSString *cybersecStatistic2;
NSString *cybersecStatistic3;
NSString *cybersecStatistic1CitationMLA;
NSString *cybersecStatistic1CitationAPA;
NSString *cybersecStatistic2CitationMLA;
NSString *cybersecStatistic2CitationAPA;
NSString *cybersecStatistic3CitationMLA;
NSString *cybersecStatistic3CitationAPA;
NSString *cybersecStatistic1Source;
NSString *cybersecStatistic2Source;
NSString *cybersecStatistic3Source;
-(IBAction)cybersecurityGo:(id)sender {
cybersecStatistic1 = #"\"In 2015, nearly 20% of global companies implemented a cybersecurity budget between $1 million and $4.9 million.\" (PricewaterhouseCoopers survey)";
cybersecStatistic2 = #"The average annual number of cybersecurity incidents is 80-90 million. There was a 38% increase in such incidents from 2014-2015.";
cybersecStatistic3 = #"USA: Over 36% of people who share passwords have shared the password associated with their banking account.";
cybersecStatistic1CitationAPA = #"Penguin Strategies. (2016, January 17). Top Cybersecurity Statistics for 2016 - Cyber Security Marketing Blog. Retrieved April 16, 2016, from http://www.marketingcyber.com/2016-cybersecurity-statistics/";
cybersecStatistic2CitationAPA = #"Smith, C. (2016, January 20). 34 Amazing Cybersecurity Statistics. Retrieved April 16, 2016, from http://expandedramblings.com/index.php/cybersecurity-statistics/";
cybersecStatistic3CitationAPA = #"Norton by Symantec. (1995-2016). Norton Cybersecurity Insights Report. Retrieved April 16, 2016, from https://us.norton.com/cyber-security-insights";
cybersecStatistic1CitationMLA = #"\"Top Cybersecurity Statistics for 2016 - Cyber Security Marketing Blog.\"Cyber Security Marketing Blog. Penguin Strategies, 17 Jan. 2016. Web. 16 Apr. 2016.";
cybersecStatistic2CitationMLA = #"Smith, Craig. \"34 Amazing Cybersecurity Statistics.\" DMR. DMR, 20 Jan. 2016. Web. 16 Apr. 2016.";
cybersecStatistic3CitationMLA = #"\"Norton Cybersecurity Insights Report.\" 2016. Norton by Symantec, 1995-2016. Web. 16 Apr. 2016.";
cybersecStatistic1Source = #"http://www.marketingcyber.com/2016-cybersecurity-statistics/";
cybersecStatistic2Source = #"http://expandedramblings.com/index.php/cybersecurity-statistics/";
cybersecStatistic3Source = #"https://us.norton.com/cyber-security-insights";
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic1 forKey:#"statistic1"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic2 forKey:#"statistic2"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic3 forKey:#"statistic3"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic1CitationMLA forKey:#"statistic1CitationMLA"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic1CitationAPA forKey:#"statistic1CitationAPA"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic2CitationMLA forKey:#"statistic2CitationMLA"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic2CitationAPA forKey:#"statistic2CitationAPA"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic3CitationMLA forKey:#"statistic3CitationMLA"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic3CitationAPA forKey:#"statistic3CitationAPA"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic1Source forKey:#"statistic1Source"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic2Source forKey:#"statistic2Source"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setObject: cybersecStatistic3Source forKey:#"statistic3Source"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Tapping a topic button takes you to the next screen, StatsViewController. It's implementation file receives the NSUserDefaults and displays the appropriate statistics. IBActions related to each statistic UIButton set the “route” for the next screen in order to display the correct citations. THIS IS WHERE SOMETHING SEEMS TO GO WRONG BECAUSE THE CITATIONS ARE DISPLAYED FOR THE LAST STAT I VIEWED (NEVER THE NEWLY ADDED STAT'S CITATION)--> I FIXED THIS ISSUE BEFORE BY CHANGING MY ViewDidLoad to a ViewWillLayoutSubviews in CitationViewController which I will explain next.
#implementation StatsViewController
NSString *whichStat;
NSString *strStat1;
NSString *strStat2;
NSString *strStat3;
-(IBAction)stat1Go:(id)sender {
whichStat = #"stat1Route";
[[NSUserDefaults standardUserDefaults] setObject:whichStat forKey:#"activeStat"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
-(IBAction)stat2Go:(id)sender {
whichStat = #"stat2Route";
[[NSUserDefaults standardUserDefaults] setObject:whichStat forKey:#"activeStat"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
-(IBAction)stat3Go:(id)sender {
whichStat = #"stat3Route";
[[NSUserDefaults standardUserDefaults] setObject:whichStat forKey:#"activeStat"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
-(void)viewWillAppear:(BOOL)animated {
whichStat = nil;
strStat1 = nil;
strStat2 = nil;
strStat3 = nil;
strStat1 = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic1"];
strStat2 = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic2"];
strStat3 = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic3"];
[_stat1 setTitle:strStat1 forState:UIControlStateNormal];
[_stat2 setTitle:strStat2 forState:UIControlStateNormal];
[_stat3 setTitle:strStat3 forState:UIControlStateNormal];
if ([strStat1 isEqual: #"more stats to come"]) {
_stat1.enabled = false;
}
else {
_stat1.enabled = true;
}
if ([strStat2 isEqual: #"more stats to come"]) {
_stat2.enabled = false;
}
else {
_stat2.enabled = true;
}
if ([strStat3 isEqual: #"more stats to come"]) {
_stat3.enabled = false;
}
else {
_stat3.enabled = true;
}
Tapping a statistic button take you to the CitationViewController, which displays the APA and MLA citations. THE CITATIONS FOR NEWLY ADDED STRINGS (SINCE APP STORE SUBMISSION) ARE NOT CORRECTLY LOADED IN THE ViewWillLayoutSubviews.
#implementation CiteViewController
NSString *citeStatPath;
NSString *citeUsingMLA;
NSString *citeUsingAPA;
NSString *sourceWebSite;
-(void)viewWillLayoutSubviews {
citeStatPath = [[NSUserDefaults standardUserDefaults] stringForKey:#"activeStat"];
if ([citeStatPath isEqualToString: #"stat1Route"]) {
citeUsingMLA = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic1CitationMLA"];
citeUsingAPA = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic1CitationAPA"];
[_citeMLA setTitle:citeUsingMLA forState:UIControlStateNormal];
[_citeAPA setTitle:citeUsingAPA forState:UIControlStateNormal];
}
else if ([citeStatPath isEqualToString:#"stat2Route"]) {
citeUsingMLA = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic2CitationMLA"];
citeUsingAPA = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic2CitationAPA"];
[_citeMLA setTitle:citeUsingMLA forState:UIControlStateNormal];
[_citeAPA setTitle:citeUsingAPA forState:UIControlStateNormal];
}
else {
citeUsingMLA = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic3CitationMLA"];
citeUsingAPA = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic3CitationAPA"];
[_citeMLA setTitle:citeUsingMLA forState:UIControlStateNormal];
[_citeAPA setTitle:citeUsingAPA forState:UIControlStateNormal];
}
}
Tapping a citation button takes you to the UIWebView which gets the URL from an NSUserDefault established and saved in TopicViewController.m. THE CORRECT WEBSITE ALSO DOES NOT APPEAR.
#implementation SourceViewController
NSString *srcStatPath;
NSString *webSite;
-(void)viewWillAppear:(BOOL)animated {
srcStatPath = [[NSUserDefaults standardUserDefaults] stringForKey:#"activeStat"];
if ([srcStatPath isEqualToString: #"stat1Route"]) {
webSite = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic1Source"];
}
else if ([srcStatPath isEqualToString:#"stat2Route"]) {
webSite = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic2Source"];
}
else {
webSite = [[NSUserDefaults standardUserDefaults] stringForKey:#"statistic3Source"];
}
NSURL *url = [NSURL URLWithString:webSite];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[_source loadRequest:request];
}
This issue occurs on iPhone Simulator and my own iOS device (iPhone 6- version 9.3.2).
Thank you in advance for the help. I am quite stuck!

Related

How to clear NSUserDefaults Data?

When I choose a language from language selection list in my app then it shows that language which I selected previously. If I clear the app from my simulator stack or clear it from xcode then run the project, after that it goes ok, and if I want to change the language again then I faced same problem. My code is given below:
- (IBAction)English:(id)sender {
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
[userDefault setObject:[NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
[userDefault synchronize];
ChooseItemVC *civc = (ChooseItemVC*)[self.storyboard instantiateViewControllerWithIdentifier:#"ChooseItemVC"];
[self.navigationController pushViewController:civc animated:YES];
}
Another language selection code:
- (IBAction)Arabic:(id)sender {
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
[userDefault setObject:[NSArray arrayWithObjects:#"ar", nil] forKey:#"AppleLanguages"];
[userDefault synchronize];
ChooseItemVC *civc = (ChooseItemVC*)[self.storyboard instantiateViewControllerWithIdentifier:#"ChooseItemVC"];
[self.navigationController pushViewController:civc animated:YES];
}
The best way to remove all user default vlaues are as follows :
Swift code:
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
UserDefaults.standard.synchronize()
Objective C
NSString *strIdentifier = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:strIdentifier];;
[[NSUserDefaults standardUserDefaults] synchronize];
Use following code to remove all existing data in user defaults, i am posting swift code, convert this to objective-c.
if let bundleID = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: bundleID)
}
To remove use this
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
[[NSUserDefaults standardUserDefaults] synchronize];
To remove you data from NSUserDefaults
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"AppleLanguages"];
For remove data from NSUserDefaults Try this:
NSString *AppDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:AppDomain];

call different method with same string in different value

I have two methods in my .m file .And i want to access by different values but in my Facebook variable gives nil value but if i use only one line and remove second line of object for key then it work fine for one method .
How i do this which work for my both methods
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[[NSUserDefaults standardUserDefaults] synchronize];
user=[defaults objectForKey:#"userid"];
facebook=[defaults objectForKey:#"FACEBOOKprofile"];
facebook =[defaults objectForKey:#"VLCC"];
if ([facebook isEqualToString:#"VLCCFACEBOOK"])
{
[self FacebookRecord];
}
else if([facebook isEqualToString:#"VLCC"])
{
[self VlccRecord];
}
assume that
Choice-1
// for accessing the both condition in same time
Initially Store the UserDefault value based on your method.
if you are access with facebook , on that time store the string like
[[NSUserDefaults standardUserDefaults] setObject:"VLCCFACEBOOK" forKey:#"FACEBOOKprofile"];
[[NSUserDefaults standardUserDefaults] synchronize];
if you are access with VLCC , on that time store the string like
[[NSUserDefaults standardUserDefaults] setObject:"VLCC" forKey:#"VLCCprofile"];
[[NSUserDefaults standardUserDefaults] synchronize];
and retrieve the both and check like
if ([[[NSUserDefaults standardUserDefaults]
objectForKey:#"FACEBOOKprofile"]isEqualToString:#"VLCCFACEBOOK"])
{
[self FacebookRecord];
}
if([[[NSUserDefaults standardUserDefaults]
objectForKey:#"VLCCprofile"] isEqualToString:#"VLCC"])
{
[self VlccRecord];
}
Choice-2
// for accessing single condition on single time
if you are access with facebook , on that time store the string like
[[NSUserDefaults standardUserDefaults] setObject:"VLCCFACEBOOK" forKey:#"FACEBOOKprofile"];
[[NSUserDefaults standardUserDefaults] synchronize];
if you are access with VLCC , on that time store the string like
[[NSUserDefaults standardUserDefaults] setObject:"VLCC" forKey:#"FACEBOOKprofile"];
[[NSUserDefaults standardUserDefaults] synchronize];
and retrieve the both and check like
if ([[[NSUserDefaults standardUserDefaults]
objectForKey:#"FACEBOOKprofile"]isEqualToString:#"VLCCFACEBOOK"])
{
[self FacebookRecord];
}
else if([[[NSUserDefaults standardUserDefaults]
objectForKey:#"FACEBOOKprofile"] isEqualToString:#"VLCC"])
{
[self VlccRecord];
}
In your code, the [self VlccRecord] method will always get called because you are overwriting the facebook variable.
facebook=[defaults objectForKey:#"FACEBOOKprofile"];
facebook =[defaults objectForKey:#"VLCC"];
If you are looking to append the two strings : Then use the stringbyAppendingString method.
int a = 10;
a = 20;
print >> a; //20
int a = 10;
print1 >> a; //10
a = 20;
print2 >> a; //20
Here,
a = facebook;
print1 = [self FacebookRecord];
print2 = [self VlccRecord];
I believe you'll understand.

UILabel text updation

I have aUILabel which I want to update.
If I will login with a user name then the UILabel will be updated with that user name,which it is doing correctly and storing the value.
Now I want whenever i will logout then the UILabel text should return the previous value which it stored deleting the new value.
Can you please help me with this.
After login I have updated my UiLabel text like this
-(void)updateUserName:(NSNotification*)noti
{
NSDictionary* userInfo = [noti userInfo];
self.user.firstName = [userInfo valueForKey:#"FirstName"];
self.user.lastName = [userInfo valueForKey:#"LastName"];
if (self.user.firstName != nil && self.user.firstName.length > 0 && self.user.lastName.length > 0)
{
self.userName.text = [NSString stringWithFormat:#"%# %#",self.user.firstName, self.user.lastName];
}
}
then after logout I need to retrieve the old data of UiLabel.
NSString *userName =[NSString stringWithFormat:#"%# %#",self.user.firstName, self.user.lastName];
[[NSUserDefaults standardUserDefaults] setObject:valueToSave forKey:#"preferenceName"];
[[NSUserDefaults standardUserDefaults] synchronize];
save username to NSUserdefaults
NSString *userName = [[NSUserDefaults standardUserDefaults]
stringForKey:#"preferenceName"];
Take the username whenever you want and assign it to UILabel name
whenever the user got Logout clear the NSuserdefaults
NSString *userName =#"";
[[NSUserDefaults standardUserDefaults] setObject:valueToSave forKey:#"preferenceName"];
[[NSUserDefaults standardUserDefaults] synchronize];

iOS - Retrieving and saving scores of a game

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];
}

NSUserDefaults doesn't save my values

I use this code to save:
[[NSUserDefaults standardUserDefaults] setValue:#"vruch" forKey:#"nastoikaIP"];
[[NSUserDefaults standardUserDefaults] synchronize];
and this code to load:
NSString* automanual = [[NSUserDefaults standardUserDefaults]
valueForKey:#"nastroikaIP"];
if ([automanual isEqualToString:#"vruch"]) {
autovruch.selectedSegmentIndex = 1;
[self obnovittext];
}
You should not use the method setValue: (from the NSKeyValueCoding protocol) but setObject: (from the NSUserDefaults class) to store the string.
[[NSUserDefaults standardUserDefaults] setObject:#"vruch" forKey:#"nastroikaIP"];
[[NSUserDefaults standardUserDefaults] synchronize];
You can retrieve the string using the method stringForKey:
NSString* automanual = [[NSUserDefaults standardUserDefaults] stringForKey:#"nastroikaIP"];
Finally, note that it is generally better to define constants for the keys you use in NSUserDefaults to avoid any mistyping errors, which may be hard to debug when they happen.
Edit
It looks like you already did a mistyping error nastoikaIP != nastroikaIP. Notice the missing/extra r letter.
Your saving a string so you need to setObject rather than setValue
[[NSUserDefaults standardUserDefaults] setObject:#"vruch" forKey:#"nastoikaIP"];
[[NSUserDefaults standardUserDefaults] synchronize];
and change it for the loading aswell
NSString* automanual = [[NSUserDefaults standardUserDefaults] objectForKey:#"nastroikaIP"];
if ([automanual isEqualToString:#"vruch"]) {
autovruch.selectedSegmentIndex = 1;
[self obnovittext];
}

Resources