I have some general questions about iphone app updates that involves sqlite db.
With the new update does the existing sqlite db get overwritten with a copy of the new one?
If the update doesn't involve any schema changes then the user should be able to reuse the existing database with their saved data, right? (if the existing database doesn't get overwritten from 1 above )
If there are some schema changes, what's the best way to transfer data from the old database into the new one? Can some one please give me guidelines and sample code?
Only files inside the app bundle are replaced. If the database file is in your app's Documents directory, it will not be replaced. (Note that if you change files inside your app bundle, the code signature will no longer be valid, and the app will not launch. So unless you are using a read-only database, it would have to be in the Documents directory.)
Yes.
What's best depends on the data. You're not going to find sample code for such a generic question. First, you need to detect that your app is running with an old DB version. Then you need to upgrade it.
To check versions:
You could use a different file name for the new schema. If Version2.db does not exist but Version1.db does, do an upgrade.
You could embed a schema version in your database. I have a table called metadata with a name and value column. I use that to store some general values, including a dataversion number. I check that number when I open the database, and if it is less than the current version, I do an upgrade.
Instead of creating a table, you could also use sqlite's built-in user_version pragma to check and store a version number.
You could check the table structure directly: look for the existence of a column or table.
To upgrade:
You could upgrade in place by using a series of SQL commands. You could even store a SQL file inside your app bundle as a resource and simply pass it along to sqlite3_exec to do all the work. (Do this inside a transaction, in case there is a problem!)
You could upgrade by copying data from one database file to a new one.
If your upgrade may run a long time (more than one second), you should display an upgrading screen, to explain to the user what is going on.
1) The database file isn't stored as part of the app bundle so no, it won't get automatically overwritten.
2) Yes - all their data will be saved. In fact, the database won't get touched at all by the update.
3) This is the tricky one - read this fantastically interesting document - especially the part on lightweight migration - if your schema changes are small and follow a certain set of rules, they will happen automatically and the user won't notice. however, if ther are major changes to the schema you will have to write your own migration code (that's in that links as well)
I've always managed to get away with running lightweight migrations myself - it's by far easier than doing it yourself.
What I do is that I create a working copy of the database in the Documents directory. The main copy comes with the bundle. When I update the app I then have the option to make a new copy over the working copy, or leave it.
Related
I have an app that uses a database of about 5000 entries.
This database is bundled in the app as a realm file.
I want to be able to update/add entries to this database regulary using REST and I think I have done it correctly - I just want to make sure.
This is how I have done it:
When the app is installed I copy the bundled database from the mainBundle to the Documents directory for read/write access. I then delete the database from the mainBundle.
When I update/add new entries to the database, they are pushed to the user using REST and inserted into the database located in the Documents directory.
When an update is released of the app, I make a check to see if the database already exists in the Documents folder - if it does I automatically remove the database in the mainBundle as it is not needed.
Am I on the right track with this? Is there a better way of doing it?
Appreciate any input!
Regards,
Erik
When I update/add new entries to the database, they are pushed to the user using REST and inserted into the database located in the Documents directory.
Technically, you can't push via REST. So I guess, you're either sending a background push notification to all installations or you're checking at application launch, whether there is a new version of the database available. That's at least what I would propose, but your requirements for getting new data out may vary.
When an update is released of the app, I make a check to see if the database already exists in the Documents folder - if it does I automatically remove the database in the mainBundle as it is not needed.
This doesn't work. The main bundle is the signed app bundle. If you would tamper the contents, that would prevent your app from launching. For that reason the access to it is limited by the OS to read-only. So this operation will always fail with an error. Instead you might properly just want to skip seeding the database from the main bundle.
I'm using sqlite in my iOS app, my database file is called data.db.
Let's suppose that I have only one table in it and i push the app to the AppStore.
In the next version I updated the data.db and added an other table and push the app to the AppStore.
So the questions are, the user who has the old version and update the app, will he have the new data.db with the 2 tables? Or does he keep the old data.db?
If he keep the old one, how can update his data.db programmatically? And if he will get the new one so it can be a bad idea if i will store his personnal data in the data.db.
When you distribute an app with a database, that database is stored in the bundle. If the user needs to update the database, the app cannot programmatically update the file in the bundle, so you generally copy the database from the bundle to the Documents folder (if you haven't already done so), and then the app can update that Documents version with new information from the user.
When you distribute updates of the app, the file in the bundle is replaced/updated, but the user's copy in the Documents folder stays there unless you explicitly remove it programmatically (or the user manually uninstalls the app). So, using your example, the database in the bundle will have the two tables (but without the user's data), and the copy in the Documents folder will have only one table (but with the user's data).
If you want a single database with the two tables, but also with the user's data, you'll have to copy the new, two table database to the Documents folder and then update this version with the user data from the old Documents database. Or alternatively, you might include a script that alters the user's database so it now includes both tables (e.g. does the necessary ALTER TABLE and CREATE TABLE).
As an aside, it's useful to keep track of what version a database is, either by including a "configuration" table that holds this information, or by availing yourself of the user_version or schema_version pragmas. That way you can programmatically inspect the database and determine what course of action you might need to take.
I'm updating an app to a whole new version (remade). Everything is going to change to be faster and less bugy. As other post suggest I cannot create another version of the model since I don't have the app code to the previous version (I started a new project). All I have is the bundle identifier for it to be an update. I will use core data but I want to delete all the old models and old data for the users that are updating, as if they deleted the app and reinstall it. How do I achieve this? or there's no need to delete anything because is a different model? All i want is to prevent app crash on launch. thanks in advance.
If you tried to open the same persistent store file with a model that doesn't allow Core Data to make sense of it then you'd raise an exception. So probably all you need to do is use a different file — remember that you get to specify the on-disk location in addPersistentStoreWithType:configuration:URL:options:error: — for your persistent store and ask NSFileManager to delete the old one.
I don't think there's a penalty for asking to delete a file that already doesn't exist so no need for any particularly complicated logic. You'd just be duplicating what the file manager does internally anyway.
Alternatively, if you prefer to keep the same file, enclose your call to addPersistentStoreWithType:... in an #try/#catch block and in the #catch just delete the existing file and try the addPersistentStoreWithType:... a second time.
I'm using a sqlite database in my iOS app. I have all its tables definitions in an .sqlite file I've placed in the "Supporting Files" group of the Xcode project, and in code I copy this file to "Documents" to be able to perform database operations. While developing, I've found that, when I need to add/remove a table or change its fields and I remove the .sqlite file from "Supporting Files" to add the new one, then I need to uninstall the app from the device or the simulator and build again to get the new database.
How could I make changes in database tables by replacing the .sqlite file without having to uninstall the app? When the app will be submitted to the App Store, will the users have to reinstall the app when a new update with changes in database is available?
EDIT. Is it possible to replace the database and to keep/copy the data the user had in the old one? Or will user loose all the stored data when downloading an app update from the Store where the .sqlite database is replaced, as if he were installing the app from scratch?
I've never submitted an app to the Store yet, I need some guidelines about how to handle app updates if I need to make changes in database tables when having such database in an .sqlite file. I'm not using Core Data.
Thanks
for it, you need to modify database by using programmatically. Means, if you want to create/add new table in database then you need to add code like Create Table.... In this case, you can't use predefine database in code.
But if you want to use database instead of writing code, then you need to rename your database and copy all old database data to new database programmatically.
Thanks
I am updating an old iOS app which used sqlite database. I changed the database structure adding columns to existing tables. Now, I am testing it on my device. If I clear my old app from iPad and then run this new updated version on it, it is working fine. But if I have the old version installed on ipad already and test this updated version, it is somehow using the old database instead of the one updated. Can some one help me why it is doing this?
My guess and to try and make a simple answer for you is this. It's likely you updated the database in the project file - which means when you run it, your new db will exist in the bundle. files in the bundle cannot be updated, so its common practice to copy the database out of the bundle and store it somewhere in the ios sandbox. I usually use the documents directory to keep it simple.
Most likely what is happening is that when you run it over a pervious install, it see's that the file is already copied over to the device so it does not touch it, however on new installs, it probably sees the database is missing so it copies it there and that is why on new installs it works fine but existing ones it does not.
Look in the app delegate or your root view controller for code that checks for the existing database and copies the database over if needed on startup.
If you need to update the database on existing installs, you would need to force the copy.
Beware though if you have data in the existing database not to overwrite it if its important. If important data is stored there, you have to either do a little shell game of getting the data and importing into the new database, or maybe a simpler way, is to run the database schema modification commands on the existing database so it is the same.
again, beware and make a copy of the local database file before you run those commands, just in case.
best of luck
In iOS, a SQLLite database is really just a file. When you used the old app, it created the schema in the database file. When you load the new app, the data remains, untouched. If you want to use the new schema, you will have to detect the old schema and update the existing data. I believe that there are documented ways to deal with this. Bryanmac's question reference seems to be a good place to start.
When you install a new version of your app, iOS actually installs it in a new directory and then copies the contents of the documents folder from the older version to the one in the newer version. If you want to just use your new db, the best way is to have this db renamed or stored in a different directory inside your app's document store.
Here's a relevant article on updating An sqlite CoreData backing store on iOS:
http://www.musicalgeometry.com/?p=1736