NSLocalizedStringFromTable change default language at runtime - ios

I'm using this line to change the default language
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:#"it"] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
and using this line to get the value
NSLocalizedStringFromTable(#"text", #"PA", nil);
Only issue is that I need to restart the app for the changes to be applied.
When i call NSLocalizedStringFromTable it always return from the language before the change
Is it possible to let the user have the option to change the local language without exiting the app?
Here is a sample project i created that demonstrate the issue
https://dl.dropboxusercontent.com/u/13431688/LocalizationTest.zip

As far as I know, it is not possible. What you could do is to have in your Localizable.strings file key-value pairs like
"en.error.general" = "An error occured.";
"fr.error.general" = "...";
then define a macro like:
#define LocalizedString(key, language) [[NSBundle mainBundle] localizedStringForKey:[NSString stringWithFormat:#"%#.%#", language, key] value:key table:nil]
and call it by LocalizedString(#"error.general", #"en");

Related

error: Trying to put the stack in unreadable memory at: 0x7ffeeafe2af0 : using userDefaults

I am doing a project in objective-c and I have to store some values in userDefaults. I am already did the same thing in the same project. It was working fine but now I am trying to add some values in userDefaults it showing error while fetch any data from userDefaults. I am adding the datas as,
NSString * totalBitValue = [NSString stringWithFormat:#"%.6f Bit",
totalValue /
[[[NSUserDefaults standardUserDefaults] objectForKey:#"Bit"] floatValue]];
[[NSUserDefaults standardUserDefaults]setObject:totalBitValue forKey:#"totalBTCValue"];
[[NSUserDefaults standardUserDefaults]setFloat:totalUSDValue forKey:#"totalUsedValue"];
[[NSUserDefaults standardUserDefaults] synchronize];
and the error as ,
error: Trying to put the stack in unreadable memory at: 0x7ffeeafe2af0
I got the error in the following line,
if( [[NSUserDefaults standardUserDefaults] objectForKey:#"CoinValue"] != nil) {
[[self ValueLabel] setText: [NSString stringWithFormat:#"%#", [[NSUserDefaults standardUserDefaults] objectForKey:#"CoinValue"] ]];
}
Anyone can help me.Thanks in advance
The reason for your issue is because your code gets recursion.
As I understand, you used NSNotificationCenter to observer key NSUserDefaultsDidChangeNotification. So whenever NSUserDefaults is updated, it will trigger defaultsChanged method. But inside it, you continue to change NSUserDefaults, set new value for totalBTCValue and totalUSDValue (as I guess) which makes defaultsChanged be called again and leads to recursion.
To fix the issue, you shouldn't update NSUserDefaults inside defaultsChanged method

Manual language with correct NumberFormatter and localizedStringWithFormat

I added a manual language section inside my iOS App where you can change the language the app should be displayed in. If someone chooses to select a manual language I override the "AppleLanguages" standardUserDefaults like so
NSString *language = [[[NSUserDefaults alloc] initWithSuiteName:kAppGroup] objectForKey:kManualLanguageKey];
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:language, nil]
forKey:#"AppleLanguages"];
Now when the user restarts the app (after terminating it) the App automatically loads the correct LocalizedStrings.
Now here is my problem:
even though this solves my problem of changing the language of the app it does not display numbers etc. correctly. Number/DateFormatter and localizedStringWithFormat depend on the [NSLocale currentLocale]. I know I could just overrite the current lokale as well like so
[[NSUserDefaults standardUserDefaults] setObject:language
forKey:#"AppleLocale"];
but then I can't get the real language/region selected in the system settings once the user decides to disable the manual language. I could store the currentLocale inside my own userDefaults before I override it but then if the user decides (for whatever reason) to change the system language while the manual language in the app is active I won't be able to get this new selected system language.
Is there any way to get the right format of Numbers and Dates without manually changing the locale property of NumberFormatter etc.?
Ok, I found a way to reset the current locale after the user disables the manual language on http://www.thetawelle.de/?p=3800
In main.m if the bool for manual language is false, I reset the current language like this:
NSArray *keysToRemove = #[#"AppleLanguages",#"NSLanguages",#"AppleLocale"];
NSLog( #"RESETTING TO USE SYSTEM LOCALE" );
#try {
for( NSString *currentKey in keysToRemove ) {
if( [defaults objectForKey:currentKey] ) {
[defaults removeObjectForKey:currentKey];
}
}
}
#catch (NSException *exception) {
// NOTHNG TO CATCH HERE
}
#finally {
[defaults synchronize];
}
after that, the current locale and language are back to the language and region selected in the system settings.

NSUserDefaults not storing values between app and custom keyboard in iOS 8

I'm trying to share data between my application and a custom keyboard extension. I've turned on App Groups in both the main application target and the custom keyboard target. In my main application, I add an object with the following:
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.mycompany.myapp"];
[userDefaults setObject:someObject forKey:#"KEY"];
Printing out [userDefaults dictionaryRepresentation] in the console reveals that this object has been saved, as does calling [userDefaults objectForKey:#"KEY"].
However, when I try to access this object in the custom keyboard extension:
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.mycompany.myapp"];
NSString *value = [userDefaults objectForKey:#"KEY"];
The value is nil and a call to [userDefaults dictionaryRepresentation] does not reveal the entry that was saved above. I'm on Xcode 6 beta 3. Any ideas?
UPDATE
Fixed in Xcode 6 beta 5
A few probable solutions are:
Your app group is not setup correctly, or you are not using the correct group identifier with initWithSuiteName:
You have not enabled network access for your keyboard. This document states the following when you have network access disabled for your keyboard (default behavior):
No shared container with containing app
It's a bug.
Set
RequestsOpenAccess = YES;
Settings:
NSUserDefaults * usrInfo = [[NSUserDefaults alloc] initWithSuiteName:#"myKeyboard"];
[usrInfo setObject:theme.icon forKey:#"themeName"]; // This is the new data;
[usrInfo synchronize];
keyboardChange:
NSUserDefaults * usrInfo = [[NSUserDefaults alloc] initWithSuiteName:#"myKeyboard"];
[usrInfo synchronize];
NSString * str = [usrInfo objectForKey:#"themeName"];
Then you can change the keyboard , for example ,change its background
I think your suite name has to start with group and match up with the container you made (source).
I found it has to follow this format: group.com.company.appname - I had something else and it didn't work.
Your group name (as set in Xcode) has to start with "group" (e.g." "group.com.myName.MyApp" (I learned this when creating a group capability since the name field is already populated with "group".) and the NSUserDefaults suiteName has to start with another "group", so "group" is there twice, e.g. "group.group.com.myName.MyApp"). I learned this by looking at the app's Library/Preferences directory when it was running in the sim. Nothing would appear there unless I used this scheme.
I still haven't been able to get the watch app to see the common group defaults file.

Store a value for the app's running time

I need to store a boolean value that would persist only for the app's running time. When the user quit the app (from the background as well) that variable should reset to default. How can I do this?
I tried constants. I keep constants in a separate .h file. In it I declared it like this.
const BOOL hasShownTutorial = NO;
And in the view controller,
if (hasShownTutorial == NO) {
[self showAppTutorial];
hasShownTutorial = YES;
}
I get an error at hasShownTutorial = YES; saying Read-only variable is not assignable.
I also tried going about this using NSUserDefaults. But the thing is the value is stored for good once you set it. Is there a way to clear it up when the app quits?
I'd appreciate your input and suggestions.
Thank you.
Store it in NSUserDefaults under a specific key.
[[NSUserDefaults standardDefaults] setBool:<myBool> forKey:#"myKey"];
Then to retrieve it later.
BOOL b = [[NSUserDefaults standardDefaults] boolForKey:#"myKey"];
If you want to clear the data.
NSString *domain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:domain];
For example, in your AppDelegate's implementation of -applicationWillTerminate:, just clear the data.
- (void)applicationWillTerminate:(UIApplication *)application
{
NSString *domain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:domain];
}
Edit: If the first method of clearing the data does not work, you can use the class method +resetStandardUserDefaults. For example the following would clear the current defaults.
[NSUserDefaults resetStandardUserDefaults];
A third possiblity is to specifically remove a property.
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"myKey"];
You can't change const value since it is a read only memory. Use static keyword instead.

iOS App default Language "en" is not applied

in Xcode 4.6.3 I set the "Localization native development region" = en.
I provide my app with Spanish, English and Russian locales.
Unfortunately when I set the Language of the Iphone Simulator to for example "German"
my app uses then the Spanish locale.
I suspect because I have a "Spanish Computer".
But I would like that the customers of my app get English if their locale is not provided by the app.
How can I ensure this?
One thing I noticed. In the "copy bundle resources" tab I see my other Localizable.strings files appear red. But I know that they are being despite red deployed...
Actual language which the app will have has a dynamic nature because it depends on a dynamic list in device settings. iOS will fall down through it and choose the 1st supported language.
Let's consider some app supports "en" and "ru". Despite that fact that "en" is much more preferable language for Portuguese locale, "ru" will be chosen because it situated higher than "en" in device settings on the screenshot below.
I had the same issue with one of my apps. What I did is force en as the second language in AppleLanguages and it's working now. You have to do that before the application starts (main). It's a bit of an ugly hack but works for now (NSLocalizedString is looking at that list to determine the language)... You have to be careful though, because you may get some weird stuff from NSLocale after you do that. For example if you want to use the - displayNameForKey:value: it won't be in sync and you'll have to restart the app so you get the correct result. so what you can do is initialize NSLocale with the first element in the [NSLocale preferredLanguages] (NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:[NSLocale preferredLanguages][0]];) and then it's going to return the expected results.
Here's what you have to do to swap the languages:
// remove what was previously stored in NSUserDefaults (otherwise the previously selected language will be still the first one in the list and your app won't be localized in the language selected in settings)
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; // make the change immediate
// reorder the languages so English is always the default fallback
NSMutableArray *mutableLanguages = [[NSLocale preferredLanguages] mutableCopy];
NSInteger enIndex = NSNotFound;
for (NSString *lang in mutableLanguages) { if ([lang isEqualToString:#"en"]) { enIndex = [mutableLanguages indexOfObject:lang]; break; } }
#try {
if ((enIndex != 0) && (enIndex != 1)) { [mutableLanguages exchangeObjectAtIndex:1 withObjectAtIndex:enIndex]; }
} #catch (NSException *exception) {
}
// save the changes
[[NSUserDefaults standardUserDefaults] setObject:mutableLanguages forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; // to make the change immediate
return UIApplicationMain(argc, argv, nil, NSStringFromClass([YourAppDelegate class]));

Resources