iOS Programming suggestion request REF sqlite/iOS app design - iphone

I currently have an iOS app that provides a sqlite DB for the data backend to the app. This data is basically a list of information. Within this app I allow the users to mark records as bookmarked (sets a value in the DB). The problem here is when I post updates to the app via the internet (update through software) for data changes, the new downloaded DB wipes out the old one thereby removing the user customizations.
Any ideas on an easy method to search the current sqlite DB for those changes, store them temporarily, then import the new DB and transfer the changes to the new DB? Could I for instance use a Core Data element at the same time as using the sqlite DB backend? Maybe a key/value pair system?
Any suggestions would be greatly appreciated.
Thanks
-LK

The way I've done it is this:
For your new version, rename your .sqlite file e.g. foo-v2.sqlite. Then, during initialization, check to see if the sqlite file for the old version is there - if so, copy over the necessary info and then delete the old sqlite file.

Related

Where is my table in the sqlite file referenced in NSPersistentCloudKitContainer in AppDelegate?

I am new to sqlite. I successfully implemented CRUD methods to CloudKit in my app. I am not using Core Data. I read in the Apple developer documentation on Remote Records that:
CloudKit stores your records in iCloud and uses subscriptions to notify your app in real time about record changes. You then use change tokens to handle these changes efficiently. Additionally, you can improve your app’s performance and support offline use by storing records in a local cache.
I am interested in this local cache. After some digging around, it looks like this cache is automatically created and stored in the container referenced in AppDelegate.swift. I put a breakpoint in my code, and in the Debug Console, I typed: po (UIApplication.shared.delegate as! AppDelegate).persistentContainer
to discover where the .sqlite file is located. It shows:
<NSPersistentCloudKitContainer: 0x600002934c40>
CoreData: debug: CoreData+CloudKit: -NSCloudKitMirroringDelegate observeChangesForStore:inPersistentStoreCoordinator:: <NSCloudKitMirroringDelegate: 0x6000007e9d40>: Observing store: <NSSQLCore: 0x7f8276e1cc70> (URL: file:///Users/xxxxxxxx/Library/Developer/CoreSimulator/Devices/30CE52B9-E246-4B40-82F4-13DBE48EB7D6/data/Containers/Data/Application/5E26076E-12F0-4E86-9B1D-BED642C01BB6/Library/Application%20Support/MyAppName.sqlite)
In a Terminal window, I typed:
open file:///Users/xxxxxxxx/Library/Developer/CoreSimulator/Devices/30CE52B9-E246-4B40-82F4-13DBE48EB7D6/data/Containers/Data/Application/5E26076E-12F0-4E86-9B1D-BED642C01BB6/Library/Application%20Support/MyAppName.sqlite
It opened the .sqlite file in Liya. I see a bunch of tables like these:
.
I inspected each table in the list. None of the table names match the name of the Record Type and none of the field names match the names of the Record Fields that I see in the CloudKit Dashboard. So, is this .sqlite file really the cache that CloudKit created locally to "mirror" the database in iCloud? If so, how do I make use of this local cache when I can't even recognize the table name or field names used in my app?
The database you are viewing is, in fact, Core Data. When you use NSPersistentCloudKitContainer with CloudKit, your app will use Core Data as the local cache.
The SQLite database that Core Data uses is not meant to be manipulated directly since the Core Data framework manages how and when data is transacted with SQLite. You should only interface with the Core Data framework in your app and not worry about what is happening under the hood in SQLite.
If you want raw access to SQLite and full control over how your data is named and structured, then you will need to do things manually. You will need to setup and manage your own SQLite transactions and then manually manage how you sync with CloudKit.
Here are a couple good options for SQLite frameworks:
SQLite.swift: https://github.com/stephencelis/SQLite.swift
GRDB: https://github.com/groue/GRDB.swift

Syncing Database (sqlite) from WebService(Json/XML) for iOS

I have a Web Service and sqlite database. In this, web service will be used to store data inside database. Now I want to include sync functionality as - Whenever application starts at that time the database will start to load its table's data through web service.
Now after some time when I update my my web service the database will be updated accordingly. My question is that what are the best practices that I must follow for this update. Should I clear whole DB and start adding all rows again(I know this will take a lot time) but If not this then how do my database will add only particular data from the web service?
Thank you.
What I suggest you is:
store all your webservice content into db first when the app starts.
display your content on the screen from db only.
again when you need to refresh or recall your data just update the database.
Thus, you will always find all your fresh data into database.
Downloading and updating the entire server data will prove expensive. It will use more bandwidth and prove costly to your customer. Rather than pushing the entire load (even for minor update), send a delta. I will suggest you to maintain version information.
When application downloads the data from web service for a said version and store it successfully in the database, set the current updated version as well in the DB.
When app starts the next time, make a light weight header request to get just the version info from the server. The server should respond to this header request with the latest data version number.
Check the version from WS with the current application data version stored in the DB. If the server has an updated version, start the sync.
The version change information should be delta i.e.
For new version, server should send only the information that is changed since the version available with the device.
You server should have capability to calculate the delta between two versions.
Delta information will typically have sections like, new data, updated data, deleted data etc.
Based on this, the iOS app will make the necessary CRUD(Create, Read, Update and Delete) operations on the DB data.
Once the iOS app updates itself, then you can update the DB version to the latest received version from server. Until then let it remain dirty for proper error handling.
Hope that helps.
I would recommend you use RestKit's superb Core Data support.
By using RKEntityMapping you can map your remote objects from JSON or XML directly to Core Data entities in your database.
RestKit will automatically maintain the database for you, inserting and updating entries as appropriate from your web service. (In my experience, I've found deleting objects requires a tiny bit of extra work depending on how RESTful your web service is).
RestKit definitely does have a learning curve attached, but it's well worth it: having deployed it a couple of times now, is definitely a much better solution than manually writing your own SQLite/Web Service syncing code.
First you need to set all webservice content into your SQLITE.and what you want to display get that data from SQLITE.and perform opertaion into that sqlite table and when once all this done you need to changes made are saved it into webservice.
Follow this way.

How to make sure sqlite DB gets updated during app update?

I have an application on app-store which is DB driven, mean all the content is residing in the sqlite DB file. Now, I need to send another update of the app with some content update in the sqlite DB, so, What's the simplest way to make it sure that my DB gets updated during app update. Note that it's static app and there's no online services included to sync DB so I am looking for something simple, without involvement of server side services etc. Awaiting response. Thanks for your consideration.
If you make a copy of your database to somewhere like the Caches folder, you should add an extra table to the database with an entry for the database version. Add something like 2011-11-23 as a string or date to a "db_version" entry. When you update the database, update that field. When your app starts, check the app bundle version of the database against the copied database. If the app bundle version is newer, copy it after deleting the old one.
If the database file is used from the app bundle without being copied, you don't need to do anything. The old version will be deleted when the app is updated.

on-the-device database for my iphone app

I want to have on-the-device database for my iphone app. It concerns with the data, which comes from dictionary consisting of 200.000 things and their definitions. It is only related with text-type data as appeared. My questions:
1- Does SQLite hold all of these data?
2- When the client downloaded my app, he/she will also have the db in his/her device. Does app store allow me to update my app's db and upload my new release? (i don't know these issues well by the way)
3- And can any client, who downloaded my app, hack and obtain my database? Is there any prevention methods? Is SQLite resilient enough against these?
1- Does SQLite hold all of these data?
Yes, SQLite can cope with this amount of data.
2- When the client downloaded my app,
he/she will also have the db in
his/her device. Does app store allow
me to update my app's db and upload my
new release? (i don't know these
issues well by the way)
The general approach is to store the SQLite database in your application bundle and then copy the database into the application's document directory on the device when the application is first run. On subsequent updates to your applciation, you should check if the database within the document directory is the same version and update it if necessary. See the existing Run NSBundle from the documents folder question/answer for more information on this.
3- And can any client, who downloaded
my app, hack and obtain my database?
Is there any prevention methods? Is
SQLite resilient enough against these?
It's fairly trivial to open up an app (the deployment package is just a zip file after all), so yes, it will be possible to obtain access to your database data. Unfortunately there's no easy way around this that I'm aware of. (You could I suppose download the data from a server when you first run you app, but it'll still be accessible on a jailbroken device.)
Sometimes, you just have to bite the bullet and accept the fact that your data is going to be ripped off.
1) sqllite can definitely hold that amount of data.
2) You can put up an option of refreshing the database in your app. That can be used to sync the local db with the server copy. Updated db can also be added with the new version of the app.
3) You can encrypt your local db using SQLCipher for protecting your application db against hacks.

How to use a pre-populated database on a coredata context

this is my first question here.
Well, I am developing an iPhone application that will use coredata, but the theres not going to be an option to insert data into the database of the app.
I want to know how to pre-populate it's database.
I thought of creating a plist with all the info and make a function to put it all into the coredata database if the database is not set yet...
but I want to know if it is the right way to do so.
Thanks all.
The easiest way is to create a desktop application with the same model (the exact same model even, just link it in). Then have Interface Builder create you a default UI for it and enter the data. Far easier than doing it on a device.
Once you have the data then include the SQLite file in your bundle and since your app is read only as you claimed; point the NSPersistentStoreCoordinator at the file in your app bundle and Bob's your uncle.
Creating an app on the desktop takes about 5 minutes and will save you far more time on the data entry side.
You can pre-create the database file (sqlite file) using your device and put that in the bundle when you distribute it. When you run the app for the first time you can move that from your applications bundle you can move it to the documents directory where core data will read it.
You can also have a function that runs at the start of your applications first run where it reads from your plist and creates the appropriate objects.