NSUserDefaults not cleared after app uninstall on simulator - ios

this may sound real NOOB! I want to check if it's the second time the user enters my application, so to keep the run count I'm using NSUserDefaults. I have implemented the following code in my rootViewController's viewDidLoad method:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSLog(#"hello %ld", (long)[userDefaults integerForKey:#"runCount"]);
if ([userDefaults integerForKey:#"runCount"] != 1) {
//not the 2nd run
[userDefaults setInteger:1 forKey:#"runCount"];
NSLog(#"not 2nd run");
} else {
//second run or more
NSLog(#"2nd run");
}
[userDefaults synchronize];
everything works fine, but the problem is that when I uninstall(delete and re-install) the application according to here and here the data should be cleared, but it is not and after re-installing the app previous data is still showing up.
I'm running my app on iOS simulator using xCode6-beta and targeting the application on iOS 8

I think this is due to a bug in the iOS8 Beta Simulator.
The expected behavior is that when the app is deleted, the NSUserDefaults for that app are deleted as well.
However, NSUserDefaults are NOT deleted when you remove an app from the simulator.
They are correctly deleted when you delete them from a physical device running iOS8.
A quick and annoying solution for now is to click, iOS Simulator -> Reset Content and Settings.
Xcode 9.2 with Simulator 10 still presents this issue. Menu option is now Hardware .. Erase All Content and Settings
I submitted a bug report btw

Since Reset Content and Settings is a nuclear option, you could consider two other options until the bug on the iOS 8/Xcode 6 GM simulator is addressed:
You could manually delete the plist file where the NSUserDefaults are stored. This is currently located at ~/Library/Developer/CoreSimulator/Devices/*some_device_id*/Library/Preferences/com.yourcompany.yourapp.plist It's a little tedious to find the right simulator to work with among the UUID directory names. EDIT: 2014-10-28 20-34-52 Correct path:
~/Library/Developer/CoreSimulator/Devices/*some_device_id*/data/Library/Preferences/com.yourcompany.yourapp.plist
You could perform "surgery" on that plist (using a run script build phase perhaps) using plistbuddy e.g.
/usr/libexec/plistbuddy -c "Set :BSDidMoveSqliteDb 0" path_to_plist

For anyone facing the same issue.
If you have more than 1 app under the same group and all of them are using app groups (ON under capabilities), then you will have to remove all the apps from the device in order for the user defaults to be cleared.
Since the user defaults are shared, even if one of the app is on the device then it will not be deleted, as that app will be using the userdefaults.

The code should work fine on the device.
Maybe some bugs in the simulator.
Try to Reset Contents and Settings for the Simulator.

it is a bug, and you can delete NSUserDefaults with following code
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];

While this is still a bug another option could be to remove the specific key(s) in NSUserDefaults. Most of the time, when testing/developing, we only care about a few keys and not everything in NSUserDefaults. If you do only care about a few keys than I propose adding removeObjectForKey:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
// ADD THIS TO SIMULATE CLEAN/EMPTY DEFAULTS, COMMENT OUT AFTER INITIAL EXECUTION.
// This will cause the TRUE case to be executed.
[userDefaults removeObjectForKey:#"runCount"]
NSLog(#"hello %ld", (long)[userDefaults integerForKey:#"runCount"]);
if ([userDefaults integerForKey:#"runCount"] != 1) {
//not the 2nd run
[userDefaults setInteger:1 forKey:#"runCount"];
NSLog(#"not 2nd run");
} else {
//second run or more
NSLog(#"2nd run");
}
[userDefaults synchronize];
Adding removeObjectForKey simulates the first run of the app, commenting it out will simulate all subsequent app executions.

In my case i found the *.plist in the following directory:
[1] /Users/SOME-USERNAME/Library/Developer/CoreSimulator/Devices/SOME-DEVICE-ID/data/Library/Preferences/SP.UserDefaultsTest.plist
Problem: Deleting the app in xCode 6(iOS 8 simulator) but the file stays on disk like mentioned above.
Solution: Deleting the located file from path [1] manually and the NSUserDefaults are gone.
So the annoying way to reset the simulator is no longer necessary.

Related

NSUserDefaults objectForKey sometimes nil

I've just noticed that a key that exists in my **NSUserDefaults**
is returning nil quite often. It seems about half the time it's
correct and the other half it's not. I say half the time, but I dont
mean that its flip-flopping, its just 40-50% I see it not work.
When I write the initial value, I call synchronize immediately.
I use this key as the applications
revision I set when a new user signs up.
The following code returns nil:
#define kDBrevision #"revision"
NSString *rev = [[NSUserDefaults standardUserDefaults] objectForKey:kDBrevision];
When I launch the app and just monitor the value (without
writing any NSUserDefaults), the value sometimes is valid
with no modifications to the NSUserDefaults at all.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSString *r = [[NSUserDefaults standardUserDefaults] objectForKey:kDBrevision];
NSLog(#"revision %#", r);
_exit(1);
I have no idea why this is happening. Im running iOS 10 on my
device connected to Xcode 8.2.1. Anyone have any ideas?
Thanks
EDIT:
I started talking to apple about fixing this and found out that if you have
file protection complete turned on, it can be the cause of this issue
showing up from time to time, however apple told me that my particular
case (which is the only one I was sure of at this time) is a bug.
The case is when you use Xcode to launch the app on the device it should
not fail like this and it occasionally does. No idea when or if it will
be fixed. Instead I moved my critical strings from the defaults to
the keychain instead.
This appears to be an Xcode 8 and/or iOS 10 bug. I ran into it myself and conclusively narrowed the case to UserDefaults intermittently returning nil when in fact there was data for the key. Specifically, I set the data once, then removed the set logic and executed only the get logic, repeatedly, and sometimes got values, sometimes got nil.
I changed my Run scheme to use Release configuration and ran the app on device without the debugger attached and the issue disappeared, that is, the get logic produced the correct value every time I executed it (~30 times).
Here is some more discussion:
iOS 10 with XCode 8 GM caused NSUserDefaults to intermittently not work
iOS 10, NSUserDefaults Does Not Work
https://forums.developer.apple.com/thread/48700
https://forums.developer.apple.com/message/143155#143155
try below code in didFinishLaunchingWithOptions
Swift 3.0
UserDefaults.standard.synchronize()
Obective - C
[[NSUserDefaults standardUserDefaults] synchronize];

iOS 10 Today extension can't read shared user defaults any more

I have an application that implements Today extension. Till iOS10 it was working fine, but now I see that it can't read keys stored in shared NSuserDefaults.
My Host app code:
NSUserDefaults *sharedPrefs = [[NSUserDefaults alloc] initWithSuiteName:kSharedGroupIdentifier];
[sharedPrefs setObject:username forKey:#"username"];
[sharedPrefs setObject:#"Test" forKey:#"test"];
[sharedPrefs synchronize];
My extension code:
NSUserDefaults *sharedPrefs = [[NSUserDefaults alloc] initWithSuiteName:kSharedGroupIdentifier];
NSString *str = [sharedPrefs valueForKey:#"test"];
And str var is always nil in extension. I have set up my App Groups in Capabilities for both Host app and extension app, and I have checked it against the settings on Apple developer portal. It is all OK. Can anyone please help, is there something different that I must do?
EDIT
Another thing that I have noticed is that I have a red exclamation mark on: "Add the Add Groups entitlement to your entitlement file", and when I fix the issue, the exclamation mark goes away, but when I close and reopen project it is there again. I have recreated provisional profiles, but still the same issue
It sounds like the issues is that your Entitlements file is missing the relevant line.
To diagnose where the issue is, start with your build settings:
Under Code Signing Entitlements there should be a file listed
Open that file and ensure that it has the App Groups key with the value that matches your kSharedGroupIdentifier
Ensure that the file is not marked read-only (this would potentially cause the "fix" to not work correctly)
Verify that all of the following match:
kSharedGroupIdentifier in both apps
kSharedGroupIdentifier and the value in your entitlements file for App Groups
Next, we can narrow the issue down to the specific key or the entire preferences domain as follows:
NSUserDefaults *sharedPrefs = [[NSUserDefaults alloc] initWithSuiteName:kSharedGroupIdentifier];
if (sharedPrefs == nil) {
NSLog(#"Error loading shared user defaults!");
}
A nil value indicates that the suite name is invalid.
Rebooting the mac solved the issue for me.
Apple RNotes WWDC Seed: Running multiple iOS simulators can cause NSUserDefaults to not work Running an iOS 8 or 9 simulator followed by an iOS 10 simulator will cause NSUserDefaults to stop working in the simulator. This can be worked around by rebooting the host Mac.
I hope it will helps you,
Thanks.

I first made a change in the Settings app,but I failed to get the newest NSUserDefaults values when my App enter foreground later

I first made a change in the Settings app,
and when my app enter foreground later, this method will be called:
-(void)appWillEnterForeground:(NSNotification *) notification{
//get standardUserDefaults
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
//save all modification
[defaults synchronize];
//change the UI
[self refreshFields];
}
the method below just refresh the UI
-(void)refreshFields{
//get standardUserDefaults
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
//get all the preference value
self.nameLabel.text=[defaults stringForKey:#"name_preference"];
}
I found that the value I get is the old value instead of the value I just set in the Settings app.
but when I restart app it will get the newest defaults value
i just want Once I changed the setting in Settings,my App will get the change when the app enter foreground again.
After I upgraded my Xcode to the newest 8.1 , and using the newest simulator provided by Xcode8.1, this problem has gone, all thing works well!So I guess it's the question of the old Xcode6 beta and simulator.

Can't read WatchKit settings bundle from iPhone app

In watchOS 2, it seems like you can't access the data from the WatchKit settings bundle from the watch extension itself, because it now runs on the watch instead of the host iPhone. A solution, which was proposed here, was to read the data on the iPhone and then transfer it to the watch.
My problem is, that I cannot only read the data from the watch, but even from my phone. In ViewController.m I have the following code to get the value of a switch:
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.de.iossoftware.SocialAppDataSharing"];
NSLog(#"%d", [[[NSUserDefaults alloc] initWithSuiteName:#"group.de.iossoftware.SocialAppDataSharing"] boolForKey:#"key_here"]);
It always returns "0", even when the switch in the settings bundle is enabled.
I'm using app groups and I made sure that I use the same identifier in the settings bundle and in the iPhone app:
Why can't I access the bundle data from my phone?
Try this:
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.de.iossoftware.SocialAppDataSharing"];
[userDefaults setValue:#55 forKey:#"myNumber"];
[userDefaults synchronize];
Execute one time in iOS simulator and then remove it and add:
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.de.iossoftware.SocialAppDataSharing"];
NSLog(#"My number: %#",[userDefaults valueForKey:#"myNumber"]
And execute one more time. You should see the value saved before
NSError *error = nil;
NSLog(#"### Directory path: %#",[[NSFileManager defaultManager]contentsOfDirectoryAtPath:[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.de.iossoftware.SocialAppDataSharing"].path error:&error]);
NSLog(#"Error: %#",error);
And in the last line you will log the file path where the group files are saved. Open it in the finder and you should see under ...../Library/Preferences/ a plist containing the NSUserdefaults created
I'm not sure exactly what you are trying to do as your questions isn't clear to me. However, with WatchOS 2, you cannot use shared group containers, you must use Watch Connectivity framework to sync data between the watch and phone. This is similar to the question here: NSUserDefaults not working on Xcode beta with Watch OS2

NSUserDefaults boolForKey not working in iOS 8

I have a simple issue but could not find an answer so far. I have a signup view that only appears once when the user first launches the app and once successful it is never shown again. I store this in NSUserDefaults as a BOOL. Here is how I check in the App delegate when the app is first launched:
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"returninguser"] != YES){
// First launch
}
else {
//not first launch
}
The problem I'm having is that at first launch, the [NSUserDefaults standardUserDefaults] boolForKey:#"returninguser"] is returning a YES. This is only an issue on iOS 8. It works fine on iOS 7.
Can anyone help with this please?
Ok, after playing with this some more, I found the answer to my question here:
NSUserDefaults not cleared after app uninstall on simulator
As mentioned above, the problem is that the simulator seems to store NSUserDefaults even after deleting the app. That's why Rob could not reproduce the issue, it works fine the first time you try but if you delete the app and try again it doesn't work.

Resources