iOS7: Saving settings to file doesn't work on device [duplicate] - ios

This question already has answers here:
File write with [NSBundle mainBundle] fails
(5 answers)
Closed 8 years ago.
I'm reading and writing variables to a text file in my app.
It works perfectly fine when testing it in the simulator, but somehow when testing it on the iPhone it can only read the file but not write/save anything
Here's my method for saving my variables ("\n" is used for line breaking):
NSString path = [[NSBundle mainBundle] pathForResource:#"settings" ofType:#"txt"];
- (void)saveSettings {
[[NSString stringWithFormat:#"%d\n%d", firstInt, secInt] writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
As I said: works in the simulator but doesn't work on any iDevice.
Does anyone got a idea why it's not working? Changing "atomically" to "NO" does nothing

You can't write to the bundle. Among other reasons because the bundle is part of the signature in the app and that can't be changed. You can write to other directories, en particular the Documents directory
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *write_file = [NSString stringWithFormat:#"%#/settings.txt",
documentsDirectory];
You will be able to write to write_file.

Short answer: You can't write into the main bundle.
Long answer: You should really use the preferences for this:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:[NSString stringWithFormat:#"%d\n%d", firstInt, secInt]
forKey:#"yourPref"];
BOOL saved = [prefs synchronize];
or even better, like that:
NSInteger firstInt = 0;
NSInteger secInt = 0;
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setInteger:firstInt forKey:#"firstInt"];
[prefs setInteger:secInt forKey:#"secInt"];
BOOL saved = [prefs synchronize];

Related

Not finding NSUserDefaults plist in simulator folder

I know that there are other same questions as mine. But I think that I have tried everything and I still can't be able to find the NSUserDefaults plist file in my simulator folder. I made sure that I got the right ID for the simulator and I wasn't able to find the NSUserDefaults plist as I want to check exactly what values are being saved. Does anyone know what is the exact name of the file that I should be searching for?
For info, I am searching in the following path:
/Users/username/Library/Developer/CoreSimulator/Devices/<device_id>/data/Library/Preferences
Does anyone know if I am doing it wrong? How can I find that file?
Thank you for your help!
you can print the location by asking at runtime.
Each time you compile and run simulator the folders may differ from before.
how to write NSUserDefaults
NSUserDefaults *userdef = [NSUserDefaults standardUserDefaults];
[userdef setObject:#"testString" forKey:#"testkey"];
[userdef synchronize]; //dont forget synchoniszing after setting new objects
how to read NSUserDefaults
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSString *result = [defs objectForKey:#"testkey"];
NSLog(#"read out userdefs = %#",result);
If you did not set any NSUserDefaults yet, there is no file.
Otherwise where is your <BundleIdentifier>.<appName>.plist ?
NSArray *path = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libraryFolder = [path objectAtIndex:0];
NSString *appID = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleIdentifier"];
NSString *userdefFile = [NSString stringWithFormat:#"%#/Preferences/%#.plist", libraryFolder, appID];
NSLog(#"NSUserDefaults File located at: %#", userdefFile);

Update Root.Plist on Compile

I have an app settings file which displays the version number for our app. The idea is to update the Root.plist on compile so that we don't have to update two places rather than one. We update theBuild settings version and would like those settings to update the Root.plist on compile.
This code extracts the information for the build settings, how do I update the Root.plist file?
NSString *appBuildNo = [[NSBundle mainBundle]objectForInfoDictionaryKey:#"CFBundleShortVersionString"];
NSString *appBuildVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"];
NSString *appBuildStr = [NSString stringWithFormat:#"%# Build %#", appBuildNo, appBuildVersion];
NSURL * settingsURL = [[NSBundle bundleWithURL:[[NSBundle mainBundle] URLForResource:#"Settings" withExtension:#"bundle"]]
URLForResource:#"Root" withExtension:#"plist"];
NSDictionary * settingsDict = [NSDictionary dictionaryWithContentsOfURL:settingsURL];
NSArray * settingsArr = [settingsDict objectForKey:#"PreferenceSpecifiers"];
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
for( NSDictionary * setting in settingsArr ){
NSString * key = [setting objectForKey:#"DefaultValue"];
[defaults setValue:appBuildStr forKey:key];
[defaults synchronize];
break;
}
The idea is that defaults updates Root.plist but it is not working. Any help would be appreciated
Droppy was very helpful in helping me to fix this. After setting up my Settings Bundle and the Root.plist file, I added the following code to my AppDelegate and called it from the didFinishLaunchingWithOptions.
- (void)updateVersionInfo
{
//This method updates the Root settings to display current Version and Build No in Settings Bundle
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *appVersionNumber = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
NSString *appBuildNo = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleShortVersionString"];
NSString *versionNumberInSettings = [NSString stringWithFormat:#"%# Build %#", appBuildNo, appVersionNumber];
[defaults setObject:versionNumberInSettings forKey:#"version"];
}
This code then adds the contents of the Version in the info.plist file to my Settings Bundle.

Does iOS Preference file automatically reset to default values

I am using the a preference(plist) file to save the user information. this file is stored in the preference folder of the app, For some logged in users this preference file is restored to default values when they switch off the ipad and restart it next morning.
Any ideas or thought on why is this occurring.
We are reading the plist like this
[[NSUserDefaults standardUserDefaults] registerDefaults:[AppSetting globalConfig]];
+ (NSDictionary *) globalConfig {
NSString* plistPath = [[NSBundle mainBundle] pathForResource:#"settings" ofType:#"plist"];
return [[[NSDictionary alloc] initWithContentsOfFile:plistPath] autorelease];
}
And after saving we write it off with
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:self.isLogIn forKey:#"isLogin"];
[[NSUserDefaults standardUserDefaults] synchronize];
some more informations... does this have any thing to do with this automatic restore. i am seeing this line in the ipads who's plist was restored..
<Error>: HID: The 'Passive' connection 'appName' access to protected services is denied.
<Error>: HID: The 'Rate Controlled' connection 'appName' access to protected services is denied.
I m sure you are writing your plist file that is there in bundle.Apple documentation says
"It is not recommended to modify your bundle content after application code signed". when you build your application again it will be overridden by default plist file what you have it in your project.
You should copy your default plist file in document directory and access it for writing. this will even go off when you delete the application from device.
To copy your plist to document directory follow
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *txtPath = [documentsDirectory stringByAppendingPathComponent:#"settings.plist"];
if ([fileManager fileExistsAtPath:txtPath] == NO) {
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"settings" ofType:#"plist"];
[fileManager copyItemAtPath:resourcePath toPath:txtPath error:&error];
}

How to set all data into a new .m file and run it in another?

So i would like to make a file called "SavedData.h" "SavedData.m" and store all my games saved data in these files...
How would I wire the whole process up to run in my "MainView.h" and "MainView.m"
I'm not that experienced with xcode...
The action in the MainView.m:
- (IBAction)btncheck:(id)sender {
if ([answer isEqualToString:#"Pizza Pie"]) {
//Name:Pizza Pie *SAVED
NSString *savestring = _textbox.text;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:savestring forKey:#"savedstring"];
[defaults synchronize];
}
_textbox is my textField
and in my SavedData.m:
//Name:Pizza Pie
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *loadstring = [defaults objectForKey:#"savedstring"];
[_textbox setText:loadstring];
}
How is this done?
& is it even possible?
I think you're aiming to save state to a file and restore it later (you wouldn't use source files for this, there's no compiler on the phone). Steps are:
Put whatever you want to save in a dictionary:
NSMutableDictionary *myState = [NSMutableDictionary dictionary];
myState[#"foo"] = #"bar";
Get a path to where you're app is allowed to save:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *pathFile = [paths[0] stringByAppendingPathComponent:#"mystate.plist"];
Save:
[myState writeToFile:pathFile atomically:YES];
Read it later:
myState = [[NSDictionary alloc] initWithContentsofFile:pathFile];
You can also build a mutable dictionary this same way (replace NSDictionary in the last line with NSMutableDictionary).

What else do I need to save a variable into disc?

I'me trying to save a variable into hard drive to load it on my app startup. I do the following:
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
votesFile = [documentsDirectory stringByAppendingPathComponent:#"votes.dat"];
Yet, this is creating no file, at least that I can see. When I try to do this:
[votes writeToFile:votesFile atomically:YES]; //votes!=nil
and then
votes = [[NSMutableDictionary alloc] initWithContentsOfFile: votesFile];
it does nothing for me, votes == nil
What am I missing here?
If you are using a NSDictionary with NSStrings as keys, and NSNumbers as values, those classes are compatible with Archiving and Unarchiving pattern, so you can use NSUserDefaults to store your data, and load it the next time you run the application.
To save your data:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:yourVotesDictionary forKey:aKey];
[defaults synchronize]; //This is very important when you finish saving all your data.
To load your data:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *votes = [defaults objectForKey:yourNSString];
As you can see, NSUserDefaults is a dictionary, and it behaves like that.
Hope it helps,
have a good day.
There can be various errors using writeToFile:atomically: which is why it returns a BOOL. You should have something like:
if(![votes writeToFile:votesFile atomically:YES]) {
NSLog(#"An error occurred");
}
If you are getting an error there you have an issue with your NSDictionary.

Resources