iOS: Force view reload after locale change - ios

I have setup my app to support a base internationalization for English and added a local for Spanish. I'm trying to provide an option to force the app to use a locale select by the user via a segmented control.
What I would like to do is have the screen "refresh" or "redraw" with the new selected locale.
Here is my action for the segmented control:
- (IBAction)segmentSwitch:(id)sender {
UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
NSInteger selectedSegment = segmentedControl.selectedSegmentIndex;
NSUserDefaults *prefs;
prefs = [NSUserDefaults standardUserDefaults];
if (selectedSegment == 0) {
[prefs setObject:#"en" forKey:#"language"];
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"English");
}
else
{
[prefs setObject:#"es" forKey:#"language"];
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"es", nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"Spanish");
}
[self.view setNeedsDisplay];
}
My hope is that the screen would refresh and display the selected language view. If I close out the app and restart, it does display new view.
Here is my viewWillAppear:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// get the saved language preference
NSUserDefaults *prefs;
prefs = [NSUserDefaults standardUserDefaults];
NSString *stringVal = [prefs stringForKey:#"language"];
// Make sure we have a valid value
if (stringVal != nil) {
// Set the language preference
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:stringVal, nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
// Turn on the appropriate segment
if ([stringVal isEqual: #"en"]) {
NSLog(#"English");
languageSwitch.selectedSegmentIndex = 0;
} else {
NSLog(#"Spanish");
languageSwitch.selectedSegmentIndex = 1;
}
} else {
// default to English
languageSwitch.selectedSegmentIndex = 0;
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
}
}
I had thought that following would force a screen refresh but it doesn't seem to be working:
[self.view setNeedsDisplay];
Any thoughts or suggestions would be appreciated. Thanks in advanced.

Related

Can't set NSUserDefaults value through variable in IOS

In my iOS app when I'm logging in I used set UserID and loginstatus into NSUserDefaults like this.
#implementation Login{
NSInteger UserId;
NSUserDefaults *preferences;
}
- (IBAction)LogInClick:(UIButton *)sender {
[preferences setInteger:UserId forKey:#"UserId"]; //UserId=40;
[preferences setBool:YES forKey:#"loginstatus"];
[preferences synchronize];
NSLog(#"All NSUserDefaults: %#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
NSString *uID = [preferences stringForKey:#"UserId"];
NSLog(#"UserID: %#",uID);
}
But the values are not setting in the NSUserDefaults. I tried to log all NSUserDefaults value and also the single UserID value but all fields are coming null.
Later I use this code to logout
- (IBAction)LogOutClick:(UIButton *)sender {
[[NSUserDefaults standardUserDefaults] setObject:0 forKey:#"UserId"];
[[NSUserDefaults standardUserDefaults] setObject:NO forKey:#"loginstatus"];
/* [preferences setInteger:0 forKey:#"UserId"];
[preferences setBool:NO forKey:#"loginstatus"];
[preferences synchronize];*/
NSLog(#"All NSUserDefaults: %#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
}
First when i logged out it all sets to zero and now the values are not setting. Can anybody tell me what the problem is?
That's because NSUserDefaults *preferences; is just a pointer. And it's value is nil, I presume. You should initialize it. For instance:
- (IBAction)LogInClick:(UIButton *)sender {
preferences = [NSUserDefaults standardUserDefaults];
[preferences setInteger:UserId forKey:#"UserId"]; //UserId=40;
[preferences setBool:YES forKey:#"loginstatus"];
[preferences synchronize];
...
May be a more logical place to initialize preferences would be an init method, or something else that you would consider appropriate for this purpose.
You haven't get the standard userdefaults reference. Change this method
- (IBAction)LogInClick:(UIButton *)sender {
preferences = [NSUserDefaults standardUserDefaults];
[preferences setInteger:UserId forKey:#"UserId"]; //UserId=40;
[preferences setBool:YES forKey:#"loginstatus"];
[preferences synchronize];
NSLog(#"All NSUserDefaults: %#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
NSString *uID = [preferences stringForKey:#"UserId"];
NSLog(#"UserID: %#",uID);
}

Save checkbox values

As many others here I am new to Xcode and would like to ask a basic question. When checking a box and leaving Xcode, this value is not saved (unchecked box) when I reopen the Xcode project.
I have seen different discussions here: e.g. how to save a checkbox value check/uncheck to NSUserDefaults but it is not working in my code. Do you have a hint where the problem is?
In my .h I have created an instance of a BOOL (called “checked“) and a UIButton is connected both as an IBAction and as an IBOutlet.
- (void)viewDidLoad{
checked = NO;
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"Negative"];
BOOL checked = [[NSUserDefaults standardUserDefaults] boolForKey:#"Negative"];
[[NSUserDefaults standardUserDefaults] synchronize];
[super viewDidLoad];
NSUserDefaults *defaults70 = [NSUserDefaults standardUserDefaults];
checked = [defaults70 boolForKey: #"boxIsChecked70"];
[self checkTheBox];
[self updateLabels];}
- (IBAction)CheckCOUTCheckButton:(id)sender {
NSUserDefaults *defaults70 = [NSUserDefaults standardUserDefaults];
if (! checked) {
[_CheckBoxCOUTButton setImage:[UIImage imageNamed:#"Checkboxcheckedimage.png"] forState:UIControlStateNormal];
checked = YES;
[defaults70 setBool:checked forKey:#"boxIsChecked70"];}
else if (checked) {
[_CheckBoxCOUTButton setImage:[UIImage imageNamed:#"Checkboxuncheckedimage.png"] forState:UIControlStateNormal];
checked = NO;
[defaults70 setBool:checked forKey:#"boxIsChecked70"];}
[defaults70 synchronize];}
- (void) checkTheBox {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (! checked) {
[_CheckBoxCOUTButton setImage:[UIImage imageNamed:#"Checkboxuncheckedimage.png"] forState:UIControlStateNormal];
}
else if (checked) {
[_CheckBoxCOUTButton setImage:[UIImage imageNamed:#"Checkboxcheckedimage.png"] forState:UIControlStateNormal];
}
- (IBAction)ClearAllFields:(id)sender {
[_CheckBoxCOUTButton setImage:[UIImage imageNamed:#"Checkboxuncheckedimage.png"] forState:UIControlStateNormal];
checked = NO;}
Your problem is an problem of scope. You are defining a second variable called checked and confusing which one you're setting.
- (void)viewDidLoad{
checked = NO;
in this line you are setting the property - ie the self.checked value to NO.
BOOL checked = [[NSUserDefaults standardUserDefaults] boolForKey:#"Negative"];
[[NSUserDefaults standardUserDefaults] synchronize];
in this line however you are declaring a NEW local variable that will only exist within viewDidLoad.
try removing the BOOL before it. When viewDidLoad returns this local variable will go out of scope and disappear.
checked = [[NSUserDefaults standardUserDefaults] boolForKey:#"Negative"];
[[NSUserDefaults standardUserDefaults] synchronize];
so later on when you set the checkbox as part of checkTheBox you're reading the property, not your local variable that you set.
let me know if this isn't clear.
I am not sure if this is your only problem, but in your viewDidLoad, you are basically setting a value before you're reading it:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"Negative"];
BOOL checked = [[NSUserDefaults standardUserDefaults] boolForKey:#"Negative"];
You probably want to do this:
BOOL checked = [[NSUserDefaults standardUserDefaults] boolForKey:#"Negative"];

NSUserDefaults Saving only last entered data

I am saving Textfield text using NSUserDefaults on button click in ViewController2
My code is
ButtonClick()
{
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordField.text forKey:#"Keywords"];
[userDefaults synchronize];
}
Then ViewDidLoad method i am Retrieving like this
-(void)viewDidLoad
{
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[keyWordArray addObject:[userDefaults objectForKey:#"Keywords"]];
[userDefaults synchronize];
}
Here i am assigning this keyWordArray to tableview
like cell.textlabel.text =[keyWordArray objectAtIndex:indexPath.row];
First i entered text(First) in textfield and click button it is showing in table like
First
Second time i entered text (second) in textfield and click button it is showing table like
First
Second
Here everything working fine. The problem is when i come to viewController2 from ViewController1. It is showing last entered value only
like
Second
what going wrong here?
Try This
- (IBAction)buttonclick:(id)sender {
[keyWordArray addObject:keyWordField.text];
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordArray forKey:#"Keywords"];
[userDefaults synchronize];
[selt.tableView reload]; //reload the table every time a new text is added
}
-(void)viewDidLoad {
if([[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"]==nil){
keyWordArray = [[NSMutableArray alloc] init];
}
else{
keyWordArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"];
}
}
Try this,
- (IBAction)buttonclick:(id)sender {
[keyWordArray addObject:keyWordField.text];
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordArray forKey:#"Keywords"];
[userDefaults synchronize];
}
and
-(void)viewDidLoad
{
NSArray *array = [[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"];
if (!array) {
keyWordArray = [[NSMutableArray alloc] init];
} else {
keyWordArray = [NSMutableArray arrayWithArray:nameArray];
}
}
Since you are overriding your
[userDefaults setObject:keyWordField.text forKey:#"Keywords"];
every then and there your every object in the array will be referring to your [userDefaults setObject:keyWordField.text forKey:#"Keywords"]; object thats y the problem comes
Because if you are navigate to another viewController. since the your user default value save in second only.
After pop to back through viewDidLoad is loaded. so far its have second string only save in User Default.
that way it display second only.
You code is overwrite the last value and remove previous values from NSUserDefault. You have to use array to stored all value and you have save array into NSUserDefault.
NSMutableArray *aryDataDefault = [[NSUserDefaults standardUserDefaults] valueForKey:#"YourKey"];
[aryDataDefault addObject:textfield.text];
[[NSUserDefaults standardUserDefaults] setObject:aryDataDefault forKey:#"YourKey"];
[[NSUserDefaults standardUserDefaults] synchronize];

How can I change application language inside the application?

I would like to change application language inside the app without restarting.
There are Localizable.strings files for both languages. All my XIBs and main Storyboard too.
Te below code can change the language only after restarting an app
main.m:
int main(int argc, char *argv[])
{
NSString *currLang = [[NSUserDefaults standardUserDefaults] stringForKey:#"Lang"];
if (!currLang) {
NSString *languageCode = [[NSLocale preferredLanguages] objectAtIndex:0];
if ([languageCode isEqualToString:#"ru"]) {
[[NSUserDefaults standardUserDefaults] setValue:languageCode forKey:#"Lang"];
}
else [[NSUserDefaults standardUserDefaults] setValue:#"en" forKey:#"Lang"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
currLang = nil;
currLang = [[NSUserDefaults standardUserDefaults] stringForKey:#"Lang"];
if ([currLang isEqualToString:#"ru"]) {
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"ru", #"en", nil]
forKey:#"AppleLanguages"];
}
else
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", #"ru", nil]
forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
There are 2 buttons (Eng & Ru) ant the method:
- (IBAction)changeLang:(UIButton *)sender
{
if ([sender isEqual:btnSetRuLang]) {
if ([[userDefaults stringForKey:#"Lang"] isEqualToString:#"ru"]) {
return;
}
[userDefaults setValue:#"ru" forKey:#"Lang"];
[userDefaults synchronize];
}
else {
if ([[userDefaults stringForKey:#"Lang"] isEqualToString:#"en"]) {
return;
}
[userDefaults setValue:#"en" forKey:#"Lang"];
[userDefaults synchronize];
}
NSString *currLang = [userDefaults stringForKey:#"Lang"];
NSString *alertBody;
if ([currLang isEqualToString:#"ru"]) {
[userDefaults setObject:[NSArray arrayWithObjects:#"ru", #"en", nil]
forKey:#"AppleLanguages"];
alertBody = #"Перезапустите приложение для смены языка";
}
else {
[userDefaults setObject:[NSArray arrayWithObjects:#"en", #"ru", nil]
forKey:#"AppleLanguages"];
alertBody = #"Restart application for change language";
}
[userDefaults synchronize];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Hom" message:alertBody delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];
}
So, how should I change lang without restarting app?
Thank you.
I have did the same in one of my application, When user changes the language I did the same and reload all my View controllers which are in navigation stack by calling setNeedsDisplay, that renders the view again with new language settings.
EDIT
for each instance of your view controller call [self setNeedsDisplay] or you can replace the self by the instance of your view controller.
I would suggest you to use
NSLocalizedStringFromTable(key, tbl, comment)
instead of NSLocalizedString(key, comment)
This way all you need to do is maintain a variable of table name. Instead of Localizable.strings, use en.strings and ru.strings files and when the language changes pass the table name as en or ru
Also as #Parser suggests, you must refresh your views.

Detect if user opened the View for the first Time In iOS

I know how I can detect if the application first time opened using NSUserDefault:
BOOL didRunBefore = [[NSUserDefaults standardUserDefaults] boolForKey:#"didRunBefore"];
if (!didRunBefore) {
//Your Launch Code
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"didRunBefore"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
The Issue: I want an Alert for ever view explaining about what features it contains and only open this alert when the app is first launched?
As an OOP programmer you can make a common public method.
+ (BOOL)checkWhetherRunBefore:(NSString *)key
{
return [[NSUserDefaults standardUserDefaults] boolForKey:key];
}
+ (void)hasRunForMyClass:(NSString *)key
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:key];
[[NSUserDefaults standardUserDefaults] synchronize];
}
And in your ViewController , you can code in the viewWillAppear or viewDidAppear like this :
- (void)viewWillAppear
{
if(![HelpController checkWhetherRunBefore:NSStringFromClass([self class])])
{
//do your thing
[HelpController hasRunForMyClass:NSStringFromClass([self class])]
}
}
You just need to put your code in viewDidLoad
viewDidLoad will run only one time when app load your view. (except low memory)
Next time you load the view again in viewDidLoad, you can check bool didRunBefore
You can use any key you want.
In FirstViewController:
BOOL didRunBefore = [[NSUserDefaults standardUserDefaults] boolForKey:#"FirstViewController_didRunBefore"];
if (!didRunBefore) {
//Your Launch Code
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"FirstViewController_didRunBefore"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
In SecondViewController:
BOOL didRunBefore = [[NSUserDefaults standardUserDefaults] boolForKey:#"SecondViewController_didRunBefore"];
if (!didRunBefore) {
//Your Launch Code
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"SecondViewController_didRunBefore"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
yo have to need to detect application first launch, you can detect t like this
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"firstRun"])
[defaults setObject:[NSDate date] forKey:#"firstRun"];
[[NSUserDefaults standardUserDefaults] synchronize];
You can then test for it later...
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"firstRun"])
{
// do something or not...
}

Resources