I'm developing an iOS app that makes use of an sqlite database directly, without using Core Data. I've the tables for the database defined in a file that I read to copy the database to Documents the first time I need it.
I'm worrying about publishing app updates in the App Store once the app submitted when such updates have changes in database tables. I asked how to handle this database updates in another post, and I was told that the way to proceed is to upload an app version that removes the former database and copies the new one into Documents with another name. I do that, but I'm still not sure of what the appropriate way to manage this issue should be. I mean, I'm currently doing this way:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Database
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults boolForKey:#"firstLaunch"] == 0) {
dispatch_queue_t queue = dispatch_queue_create(DatabaseQueue, NULL);
dispatch_async(queue,^{
[self replaceDatabase:#"former_database.sqlite" withDatabase:#"new_database.sqlite"];
[self doDataInsertions];
[defaults setBool:1 forKey:#"firstLaunch"];
});
dispatch_release(queue);
}
}
But I don´t know if this will work when a user will download and install an update. When installing an update, are the values in NSUserDefaults kept? I suppose this scenario, managing database updates when updating app version in App Store, is a common one, so could somebody clarify me what the correct way to manage this is? I don't completely understand how the app updates submission thing work, this will be my first submission.
Thanks so much
Related
I'm using NSUserDefaults in my iOS app to record some specific info about the user's receipt state.
I'd like to confirm:
If the user quits the app, will those defaults remain?
Are they global, for example I'm currently using the following line to either get or set them and across different methods. I just want to be certain the data within it persists - so if I set in method1 then later method2 I use the same line to get, it will have whatever I set in method1:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
If the user quits the app, will those defaults remain?
Yes, they are persistent.
Are they global?
Global in the sense of your whole app: Yes.
Global in the sense of across apps: No. They are in the app's sandbox.
From the NSUserDefaults documentation (see https://developer.apple.com/documentation/foundation/nsuserdefaults?language=objc)
With the exception of managed devices in educational institutions, a user’s defaults are stored locally on a single device, and persisted for backup and restore. To synchronize preferences and other data across a user’s connected devices, use NSUbiquitousKeyValueStore instead.
So for your first question the answer is yes.
Accordind to your second question, doc says:
At runtime, you use NSUserDefaults objects to read the defaults that your app uses from a user’s defaults database. NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value. When you set a default value, it’s changed synchronously within your process, and asynchronously to persistent storage and other processes.
And even so, it declares that the class is thread safe, so you can be sure about persistent results (for your second answer).
Additionally with #Nikolai Ruhe answer.
if I set in method1 then later method2 I use the same line to get, it will have whatever I set in method1: NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
The UserDefaults class is thread-safe.
Two further points.
The uselessness of synchronize has grown up gradually through versions of iOS. It used to be essential; then advisable; then unnecessary. I can’t give you an exact timeline but a lot of it depends on how far back in iOS you want your app to work.
If you try to test some of these things in Xcode, beware. Up to and including iOS 11, synchronize does not write all the way to disk, but only puts data in a “lazy write” queue. Pressing the Stop button in Xcode (or pressing Run and allowing Xcode to stop the previous running app automatically) shuts everything down abruptly, more abruptly than anything a user can do, and the lazy writes are not written out, but lost. This is confusing while you are resting!! I filed a report on it and was told by Apple that (as Microfot would put it) “This behaviour is by design”.
But just to be clear: that second point does not present a problem for real apps in a real environment, only when you are trying to test “save and restart” scenarios. Waiting 5-10 seconds seems to be long enough for the flushed data to make it all the way to disk.
This is how it is accomplished in my app:
I keep the data in iCloud.
I need to do some time consuming thing for users who already used my app. But this will also start for completely new users... they just downloaded my app from AppStore for the first time. And this is not expected.
How can I determine that the app is running, but downloaded from AppStore for the first time?
What I could do, but I did not:
put any boolean data in the Keychain, and then check if it exists.
Since you have no non-app end to distinguish users Keychain as you mentioned is your only app persistance option that will survive app uninstalling. Only device Reset to factory settings would remove it.
you can use NSUserDefaults . if appDelegate.m ->didFinishLaunchingWithOptions use this code :
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
if([userDefaults objectForKey:#"first_time"] == nil){
[userDefaults setObject:#"1" forKey:#"first_time"];
//do whatever you need
}
this condition will satisfied only once after installation .
After looking at a bunch of SO posts about detecting if this is a fresh install or not, I'm assuming what I want to do is impossible, but I'm going to ask just in case there's a trick I'm unsure of.
I am building an SDK to be integrated into apps, and I want to be able to tell when the SDK gets initialized for the very first time if it's from a brand new install, or from an app update which included our SDK.
I could have the integrator to call something like [MySDK initializeIsNewInstall:YES/NO] and force them to figure out which it is (using NSDefaults or whatever), but I'd rather be able to figure it out automatically somehow.
If anyone has any ideas, that would be great.
I would like to suggest pretty good trick by using [NSUserDefaults standardUserDefaults]
do it like this,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if([[NSUserDefaults standardUserDefaults] boolForKey:#"isApplicationUpdated"]){
// application was updated//
// make another userDefaults to store version number and confirm if it is updated here.
}
else{
[[NSUserDefaults standardUserDefaults] setBookForKey:#"isApplicationUpdated"]
// as for the first time application would not find this key and you can use it after you have updated the app do stuff here
}
Afaik the only way to detect whether your app was updated or freshly installed in your case is to check your persistence for something that should be there from a previous version. For future checks you can add your own flag to your persistence.
I'm trying to make a Core Data persistence store logic where:
If it's the first time the user is launching the app, all the data gets generated inside the app and gets loaded (and when he/she exists app, that's the first time the data is getting saved to the persistent store)
If it's not the first time the user is launching the app, then all the data gets loaded from existing Core Data persistent store.
How would you check if it's the first time the user is launching the app?
You can store the information with NSUserDefaults.
You set a variable to TRUE when the app launches for the first time.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if([userDefaults boolForKey:#"notFirstLaunch"] == false)
{
//do stuff on first launch.
[userDefaults setBool:YES forKey:#"notFirstLaunch"];
[userDefaults synchronize];
}
You can also store the app Version to update the database on App updates.
This tutorial is big help.
Core Data on iOS 5 Tutorial: How To Preload and Import Existing Data
I want to be able to display an alert describing what's new when an app has been updated. What's the best way to do this, especially considering iOS 7 automatically updates apps? Thanks!
You can store the app version in NSUserDefaults. Then if the old app version != current app version you can display your dialog
Version #:
NSString * version = [[NSBundle mainBundle] objectForInfoDictionaryKey: #"CFBundleShortVersionString"];
Set:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:version forKey:#"appVersion"];
Get:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults objectForKey:#"appVersion"];
When the user starts your app, check a version string in user defaults or a file or database.
If you want to do it around the time the app is updated, you might be able to use push notifications in conjunction with the version check. I don't know whether you can get the new app to check the version in the background, though (never used push notifications myself).
Checkout my question I've made some weeks ago (NSUserDefaults behaviour with app update). I think can solve your problem.
The idea is to use NSUserDefaults to store the last version that your device have ever ran, and if a greater version than the one I've got stored in the NSUserDefault object is going to be run, then you do whatever you want to do, in this case displaying an alert describing what's new when the app has been updated.