How to update the CloudKit schema after the app has been released to the AppStore - swift

I recently had an issue with one of my production apps that use Core Data and CloudKit where data wasn't syncing between devices, after a little bit of research I found out that the schema in the private CloudKit container needed to be initialized; which I never did.
The part I'm still not 100% sure is when to run the initializeCloudKitSchema method after the app has been released to the AppStore. I see that Apple recommends running it when testing by using #if DEBUG, but... do you really want to run it every time you compile in Xcode?
Here is how I understand it at this point...
App release, call initializeCloudKitSchema() to match schemas between Core Data and CloudKit.
Added or deleted and attribute, call initializeCloudKitSchema() to update the CloudKit schema.
Renamed an attribute, call initializeCloudKitSchema() to update the CloudKit schema.
Etc.
If my assumption above is correct, calling the initializeCloudKitSchema() method during development would update the schema in CloudKit before the new app version is released in the AppStore, therefore creating an issue for existing users with previous versions of the app since they will not have the latest code but will be using the latest schema which contains the new attributes.
Can someone please share their method of handling schema updates in CloudKit after the app has been released to the AppStore?
Code:
do {
try container.initializeCloudKitSchema()
} catch {
print(error)
}

In my case, I didn't even need to run the initializeCloudKitSchema() method. Here is what I did that worked for me.
I tested locally with two devices and made sure everything was syncing as expected. This of course was done in Xcode within the sandbox environment using testing login accounts.
Then I went to the development CloudKit container and clicked on the Deploy Schema Changes.
Lastly I went and downloaded the app directly from the App Store on two different devices using a production/regular user account and tested it. Everything worked as expected.
Done
In theory, it looks like you need to deploy the schema to the Production CloudKit container once you're satisfied with the schema and the results in the testing environments by doing the above or possibly calling the initializeCloudKitSchema() which I didn't try.
Side notes: It looks like once you deploy your schema to the Production CloudKit container you no longer can delete or rename Entities or Attributes. Also, you will have to do the above every time you update the Core Data schema. Keep in mind that if you add or remove Entities or Attributes in Core Data, you must create a new version of the Core Data container to do what is called a light migration.

Related

Error CloudKit Dashboard - There was a problem loading the environment's status

Good day!
In CloudKit Dashboard I get the error:
There was a problem loading the environment’s status
This happens when I select the action "Deploy Schema to Production..." for the "Development" schema:
I have a released application using CloudKit (respectively, there are two working schemes - Development and Production). Before the release of the application, the Development schema in CloudKit Dashboard was translated into Production (Deploy schema to production).
Now I needed to make changes to the schema.
A new field and indexes for it, as well as indexes for an existing field, have been added to the Development schema.
Now I am trying to move the schema from Development to Production in CloudKit Dashboard (so that my changes show up in Production) and
this error persists, is there any other way you can update the Production schema or fix this error?
There can be a lot of strange errors in the CloudKit dashboard. Here are a few suggestions:
Try again later (and always do a hard refresh when you do). Sometimes the error is temporary.
Try in a different web browser. Support for Chrome has improved lately, but there were times when Safari was the only way to make certain things happen.
Create a new CloudKit container, rebuild your schema, and then try to deploy. I've had certain bugs never go away within a particular container and I've had to start over fresh.
If the issue persists, submit a Feedback to the CloudKit team. They have fixed things within a day or two for me in the past.
Aside from that, your particular error isn't terribly descriptive and it's most likely something on Apple's end.
I found out that it runs into a client-side timeout of 1 minute, but the server takes longer. You can kill the timeout with
var id = window.setTimeout(function() {}, 0);
while (id--) {
window.clearTimeout(id); // will do nothing if no timeout with id is present
}
For details, see https://stackoverflow.com/a/67862078/

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.

Overwrite database or update (iPhone)?

I have a content based, read-only iPhone app. Users can select favorite topics, which I need to track. Some topics I'd like to make available between app updates through the App Store. I'll need to track if users have downloaded these particular topics or not until the App Store update is available. This approach will consist of two tables for user tracking. All other tables contain mainly static content, save any new downloaded entries.
Before I began tracking user content, I'd always deploy the database on app updates. An overwrite - simple. But now I need to track certain user configurations. Rather than trying to keep track of which app version a user has and running through a list of sql scripts in the correct order, so the user is at the right database version, I'm thiking to use two databases. One contains static content and the other user data. The static content database is always overwritten. That keeps things simple. The database currently is 250kb. It will grow very slowly.
I have plans to use SDK 3.0 push notification and peer-to-peer as well, which will store any user config data in the user database.
Any one see problems with this approach?
This sounds alright to me. If you're using SQLite, you may want to look into the ATTACH DATABASE command, which lets you keep two databases open on the same connection.