If a new version is not backward compatible with previous version's data, what is the best way to ensure NSUserDefaults is deleted upon upgrade?
A simple way would be to keep a default that tracks whether the upgrade process has been performed. The new version would check for it, and if it hasn't been set, perform the upgrade procedure and set the value to make sure the process isn't performed twice. Like this:
static NSString * const kUserDefaultsDidUpgradeKey = #"didUpgrade";
NSUserDefaults *ud = NSUserDefaults.standardUserDefaults;
if (![ud boolForKey:kUserDefaultsDidUpgradeKey]) {
// Delete the keys here
[ud setBool:YES forKey:kUserDefaultsDidUpgradeKey];
}
However, assuming that you would want to handle other version migrations in the future, a more robust way would be to write the app version to user defaults so that when the app is updated, the new version can check the version key to see what the previous version was, and run the upgrade process accordingly.
Related
I am creating a new feature in one of my apps to show a "What's New" page. I have this all working as expected and it compares the last version (stored) to the current version, then updates the current version once the feature list is shown.
This all works great and as expected. The issue I have now is determining if a user already has the app installed.
Case 1) If the user is a completely new user and it is the first time they have downloaded the app, then the new feature list should not be shown.
Case 2) If they already had the app installed and are updating their app to a new version, then we need to show the new feature list.
The part I need help with is Case 2. How can you determine if the app is already installed by the user, without having to release a minor update just to set a currentInstalledVersion variable beforehand?
if(currentInstalledVersion)
{
if(currentInstalledVersion < actualCurrentVersion)
{
// user upgraded
}
}
else
{
if(someOtherDataSavedOnDiskExists)
{
// user had the app with a version before you implemented currentInstalledVersion and is updating
}
else
{
// fresh install
}
}
Update based on below comment
Okay in that case, there is no built-in mechanism to help you with this. Until you implement a way yourself (with this flag), you can't check. However, if you have any kind of other flags or data you've written to NSUserDefaults for instance, you can check that immediately on startup to see if those values are set which would tell you it is an existing user that just installed the app (only check the other flags if currentInstalledVersion is not set). If you have not written any data to disk or to NSUserDefaults then you are out of luck for your initial release of this feature.
I updated the code above to reflect this.
You could use NSUserDefault and set a bool to check if it's a new user.
ex:
if(![[NSUserDefaults standardUserDefaults] boolForKey:#"user"]){
// it's a new user
[[NSUserDefaults standardUserDefaults] setBool:YES ForKey:#"user"];
}
The boolForKey: method would return NO if the default was not set.
I need to reset by database and userdefaults value in my OS X app. How can I do it? In IOS app we have an option like 'Reset contents and settings'. But I don't see such an option when I run OS X app. What I'm doing right now is, drill down to /users/library and delete the .storedata file under my project folder. But with this method I am not able to reset my userdefaults value. Is there any other way out? I am new to OS X programing.
Thanks in advance!
You will need to manually nil the values of your NSUserDefaults and delete the database al-together and then recreate it. Best option would be to include an empty database and copy it over to the Library folder (or wherever you access it) if it does not exist.
I have this in a DebugViewController:
- (void)removeUserDefaults {
[[NSUserDefaults standardUserDefaults] setPersistentDomain:[NSDictionary dictionary] forName:[[NSBundle mainBundle] bundleIdentifier]];
}
Then I can delete the UserDefaults with a Button-Press.
I have an app on the App Store, and I want to make some changes that will not effect users that previously downloaded my app.
Is there a way to determine if the user has previously downloaded my app?
Incase anyone is still wondering, a great solution to this problem (assuming you don't already have it) is using the Keychain, which persists through app installation/uninstalls. This library allows you to access the Keychain using NSDictionary-like syntax.
https://github.com/nicklockwood/FXKeychain
So you could implement a function like this:
-(BOOL)alreadyInstalled
{
NSString *installDate = [[FXKeychain defaultKeychain] objectForKey:#"InstallDate"];
if (!installDate)
{
NSString *newInstallDate = [NSString stringWithFormat:#"%i", [[NSDate date] timeIntervalSince1970]];
[[FXKeychain defaultKeychain] setObject:newInstallDate forKey:#"InstallDate"]
return NO;
}
return YES;
}
I don't know a great way to do this but there are some tricks you can do, e.g.:
Look for some data that your application generates. If the data already exists then it's not an update (or an update that completed previously);
Prepare yourself for this, even if this means issuing an intermediate update to your application, then go back to #1. See: How to tell if an iOS application has been newly installed or updated?
What will be the best way to check that application is already installed or being installed for the first time.
Bundle version and saving it in user defaults.
EDIT:
There are three things to note here.
Bundle version: This is the version of the your application that you want to release.
Old version: This will indicate previous version of your application. We will store this in user defaults so that we will know what was the old version when updating our application. This will obviously be nil if your bundle version is 1.0.
Target version: This indicates the version the user is targeting. We will discuss this later.
So, condition such as
bundleVersion > oldVersion or
if(isVersionBetter:myBundleVersion thanVersion:oldVersion)
would either mean we want to create our database (in this case bundle version would be 1.0 and old version will be nil) or update our database (in this case bundle version would be something greater than 1.0 and hence old version would not be nil).
Thus, as we can see, creation of database means user is installing app for the first time. Updating database means user has already installed the app and is updating the database.
But, there might also be a case when you want to update your app and want to keep the database as it is. That is, only UI updating.
Here, target version comes into picture.
As mentioned above, target version is the version the user is targeting. All would work same as above if user is targeting the bundle version. But if user is targeting some other version than bundle version, we would skip database updating part, thus allowing only the UI to change.
So, the final statement would be something like this:
if( bundleVersion == targetVersion AND bundleVersion > oldVersion ) {
// Either create or update the database.
}else {
// Do nothing. Skips database updating and allows UI update.
}
Thus, your database function would look something like this
-(void) initWithTargetVersion:(NSString *) targetVersion {
NSString *oldDatabaseVersion = [[NSUserDefaults standardUserDefaults] stringForKey:#"OldDatabaseVersion"];
NSString *bundleDatabaseVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
if([bundleDatabaseVersion isEqualToString:targetVersion] && [self isVersionBetter:oldDatabaseVersion new:targetVersion]) {
// Create or update the database.
}else {
// Do nothing.
}
}
where user would pass the target version as follows:
[[DatabaseManager sharedManager] initWithTargetVersion:#"1.0"];
I have the Facebook iOS SDK set up in my app. However, I have trouble determining when my session is finished. How to check if it's finished, and where (how) to store the access token received by the login?
I need to determine whether I have the access token or not right from the beginning so I know whether to log in again, or go forward in the app.
Are you familiar with NSUserDefaults ? It is for storing preferences for your app.
They are extremely easy to use, and probably what you are looking for. So it's just something like ..
NSUserDefaults *factoids;
NSString *whateverIDstring; // make this a property for convenience
factoids = [NSUserDefaults standardUserDefaults];
self.whateverIDstring = [factoids stringForKey:#"storeTheStringHere"];
if ( ( whateverIDstring == Nil ) || ( [whateverIDstring isEqualToString:#""] ) )
// it does not yet exist, so try to make a new one...
else
// we already made one last time the program ran
// when you make a new one, save it in the prefs file like this...
[factoids setObject:yourNewString forKey:#"storeTheStringHere"];
[factoids synchronize];
Hope it helps!
ONE get the preferences in to 'factoids' as in the example above
TWO decide on a name for your preference. 'storeTheStringHere' in the example.
THREE get your string 'whateverIDstring' in the example using stringForKey:
FOUR check if it is either nil or blank. if so, start fresh.
FIVE once you get the value, save it as shown!
Hope it helps!