iOS data base architectural decision - ios

Newbie question.
I will need to have a data base from about 200 UIImages (single of them less than 500kb size) for iPad app. Customer want to have possibility to change set of this images from time to time without releasing new version of app in appstore and app must work without connection to the web (local data base on a device). I don't see how this can be done simultaneously, I see only one common option here:
Image data base would be stored on a server, what app customer will be able to change anytime. User will need to have web connection and every time he will start the application - existing data base will load into the app.
Main questions here:
is it possible to update data base on user's device without releasing new version of app and what data base managing system is more proper to this situation(SQLite, MySQL etc...)?

Q : is it possible to update data base on user's device without releasing new version of app?
A : Yes. It is possible.
SQLite will be perfect for you.

The photographs reside on the web server.
A number of start-off photographs may reside within the boundle so that the app is not really empty at start.
However, when downloading the app, the user must be online. In most cases he would still be online directly afterwards when he launches the app for the first time.
The server provides two services:
A quick one that just provides a version number of the
photo-database content and/or the date of the last change to the
photographs on the server.
The app frequently (not more than daily I would say) checks wether there are new images on the server or not.
If they are then the user is asked, whether he wants to download them.
If the user says YES then the app sends the version number and/or last date and/or IDs of all local photographs to the server and the
server provides the information about which photographs have been
added and where to download that very photograph and which have to
be deleted.
Then you add or delete or update the photographs from the download source given by the server. (That may well be an URL to the
very same server of course.)
For 200 data sets I would strongly suggest core data with SQLite - the standard stuff.
You may then think of holding the image data in the file system or in NSData properties within the database.

Related

Difference between three firebase storage download methods

I couldn't find resources discussing the difference between the three download methods in the firebase storage documentation and pros/cons of each. I would like some clarification about the firebase storage documentation.
My App
Displays 100 images ranging from 10 KB-500 KB in size on a table view
Will be used in a location where internet connection and/or phone service could be very weak
Could be used by many users
3 methods for downloading from Firebase storage
Download to NSData in memory
This is the easiest way to quickly download a file, but it must load entire contents of your file into memory. If you request a file larger than your app's available memory, your app will crash. To protect against memory issues, make sure to set the max size to something you know your app can handle, or use another download method.
Question: I tried this method to display 100 images that were 10KB-500KB in size on my table view cells. Although my app didn't crash, as I scrolled through my table, my memory usage increased to 268 mb. Would this method not be recommended for displaying a lot of images?
Download to an NSURL representing a file on device
The writeToFile:completion: method downloads a file directly to a local device. Use this if your users want to have access to the file while offline or to share in a different app.
Question: Does that mean all images from firebase storage will be downloaded on user's phone? Does that mean that the app will be taking up a large percentage of the available storage on the phone?
Generate an NSURL representing the file online
If you already have download infrastructure based around URLs, or just want a URL to share, you can get the download URL for a file by calling the downloadURLWithCompletion: method on a storage reference.
Question: Does this method require a strong internet connection and/or phone service connection to work?
Generally, your memory usage should not be affected by the method of retrieval. As long as you're displaying the 100 images, their data will be stored in the memory and should have the same size if they're identically formatted/compressed.
Either way you go with, I suggest you implement pagination (for your convenience, this question's answer might serve as a good implementation reference/guide) to possibly decrease the memory and network usage.
Now, down to comparing the methods:
Method 1
...but it must load entire contents of your file into memory.
This line might throw some people off thinking it's a
memory-inefficient solution, when all it really means is that you
cannot retrieve parts of the data, you can only download the entire
file. In the case of storing images, you probably would want that for
the data to make sense.
If your application needs to download the images every time the users
access it (i.e if your images are regularly updated), then this
method will probably suit you best. The images will be downloaded
every time the application starts, then they'll get discarded when
you kill it.
You stated that a part of your user base might have a weak internet
connection and so the next method might be more efficient and
user-friendly
Method 2
First off, the answers to your questions:
Yes. The images downloaded using this method will be stored on the users' devices.
The images should take up about the same size they're taking on Firebase storage.
Secondly, if you plan to use this method, then I suggest you store a
timestamp (or any sort of marker) in your database for when the last
change to the images occurred. Then, every time the app opens up, do
the following flow:
If no images are downloaded -> download images and store the database timestamp locally
If the local timestamp does not equal the timestamp on the database -> download images and store the new timestamp locally
Else -> use the images you already have, they should be identical to the ones in Firebase storage
That would be the best way to go if your network usage priority is
higher than that of the local storage.
And finally...
Method 3 (not really)
This is not a data download method, this simply generates a
download URL given a reference to the child. You can then use that
URL to download the data in your app or elsewhere as long as the used
app or API is authorized to access your Firebase storage.
Update:
The URL is generated from a Firebase reference (FIRDatabase.database().reference().child("exampleReference")) and would look like this: (Note: this is a fake link that will not actually work, just used for illustration purpose)
https://firebasestorage.googleapis.com/v0/b/projectName.appspot.com/o/somePathHere%2FchildName%2FsomeOtherChildName%2FimageName.jpg?alt=media&token=1a8f83a7-95xf-4d3s-nf9b-99a274927bcb
If you simply try to access that link you generate through any regular web-browser (assuming you don't have any Firebase rule that conflicts with that in your project), you can directly download that image from anywhere, not just through your app.
So in conclusion, this "Method" does not download data from Firebase storage, it just returns a download URL for your data in case you want a direct link.

Ship iOS app with pre-populated Parse datastore

Given the recent addition of local datastore for iOS to Parse, it should be possible to rely exclusively on Parse to manage app's database, thus totally avoiding Core Data. Does this sound like a good idea? What would be the pros and cons of such an approach?
In particular, I am wondering whether it will be possible to pre-populate Parse local datastore with some data, and include this database as a part of the app when submitting to appstore.
UPDATE
From the comments that were posted, it seems that people misunderstood my intended use case. Sorry guys, I should have made my question more clear from the beginning. Let me clarify it now, anyway.
So, there is some amount of data in Parse database on the web, same for every user, e.g. a catalogue of books. It will be updated every now and then. What I want is to publish an app on App Store which is pre-populated with Parse data store, as it stands at the moment when the app is published. For that to happen, I'd like to pin all available data when building my app and ship that data store along with the app. The problem is that the pinned data will be stored on device's (or emulator's) file system, it won't be part of the project. That's why if I build the app and submit it to app store, the data won'd be included.
Any suggestions how to attach the local data store to the app?
The local data store is stored in the sandboxed part of the filesystem in iOS. When you package the store with the app, it'll live in the signed application folder, not in the location Parse expects it to be.
So, if you were looking to do this, you'd need to include your default local data store in the application on building/submission, and copy it into the location Parse expects it to be in (which is Library/Private Documents/Parse and the file is called ParseOfflineStore) when your application starts up. This must happen before you call enableLocalDatastore, or an empty one will be initialized.
It should be possible!
Read this in the docs. Parse has a highly resourceful and fully documented guide for their backend.
https://parse.com/docs/ios_guide#localdatastore
Per my comment above concerning didFinishLaunchingWithOptions; it has been a place for your to create objects on launch, I have been doing that for a long time. Especially with channels. However, by enabling the local data store you can access those objects you pinned or created with a simple query with no reachability per your concern. Either way they both are created on disk. Core Data has a lot more cons. Especially with NSFetchedResultsController and the flexibility it offers. It's all up to you what you want to do with your app. PFQueryTableViewController isn't bad but if your direction and vision for your app is to be exclusively Parse then why not. It's a great feature. However I didn't see anything in the docs about the local queries effecting your limit so I would suggest looking into that if you have a large audience performing numerous queries per second.
Take advantage of their docs. They do a great job at keeping us informed.

iOS app: Pre-populated large database not allowed - alternatives?

So my iOS app has just been rejected because it's storing too much non-user-created data in the SQLite database, which lives in the Documents folder.
The app basically involves a relatively large library of images -- around 60-or-so megabytes of them to start, and there are also in-app purchases which each add an additional 60-or-so mb of images. Furthermore, the user can add their own images to the library.
Right now everything (images and all) is stored in an SQLite database, which is generated when the app is first launched. As the user adds more images, or purchases image packs, those images are added to the database. To the user, all the images (user-generated or not) behave the same in the app.
But Apple won't allow this: I can't have all that data stored in the SQLite database in the Documents folder unless I set it specifically NOT to back up to iCloud, as it's all recreatable data.
But if I set it to not back up, then the user-generated data won't back up either, which I definitely don't want.
Any suggestions how I might "split up" the database, such that all the user-generated stuff can be backed up, but the included-or-purchased stuff isn't?
The reason you are being rejected is not following the Data Storage Guidelines. Data created or edited by the user belongs within NSDocumentsDirectory, while application data should be stored elsewhere (i.e., the Application Support directory). These requirements are a result of how iCloud backup and disk space purging work on iOS.
For a Core Data application, this means your persistent stores must be split into two different sets of files, in two different locations. This, in turn, ends up driving much of the application architecture and data model. To have relationships between the user data and application data, for instance, you must use two different managed object model configurations and the relationship must be a fetched property.
There is more detail on how to implement this in this answer.
An alternative for your specific case would be to save the images on the file system, in the caches directory or elsewhere. User images could exist in NSDocumentsDirectory while application images could exist in NSCachesDirectory. This would remove the images from Core Data and instead your model objects would have the path to the image on the file system. This would be a short term fix to get you through submission, and would probably work.
One option will be, storing your data to a server and calling is using web service. During first launch. Or as per requirement.

Multi dimension Lookup Table

I need to define a large amount of data to be stored within an app and used as a lookup table. For instance, I have an array of manufacturer names, each with a mfg code. Each manufacturer can make different products, each with their own code as well.
A,7 could be deciphered to mean
Manufacturer: Apple(A)
Product: MacMini(7)
I see several ways of defining this, but I'm not sure which would be best.
Option 1) #define these constants in a separate header file such as:
#define MFG_APPLE #"A"
#define MFG_DELL #"B"
#define PRODUCT_MAC_MINI 7
#define PRODUCT_INSPIRON 2
Option 2) create a dictionary object filled with dictionary objects to allow me to index through them easier.
Option 3) use core data to create a database of these mfgs and products and relationships.
If option 2 or 3 is suggested, are there easy ways to pre-populate these data structures instead of hard-coding them to populate during program startup?
Option 4) Create a web service to tie this back to a server, where the data can be updated more often. A JSON query will send the mfg and product codes to the server, where it can respond with the mfg and product names.
You should consider the following: If the database is shipped with the app, you will have to release an update for the app each time the database must be updated. So the question is, how frequently will you have to update the data? If it's fine to update the database once every couple of months or maybe just once a year, shipping the database with your app might be an option, if you need to update it every month or even weekly, you should definitely host the database somewhere on the web; releasing an update in such short intervals is not a feasible option.
Another thing you should consider: If the database exists solely as a web service and each look up requires a JSON call to the server, it won't be possible to perform a lookup if the user is offline (currently has no network access for whatever reason). Also each lookup costs the user traffic, so if the user has a monthly limit, yet needs to perform plenty of lookups a day, using your app may quickly cause him to exceed that monthly limit, leaving him without any Internet service (or a very throttled one) in the end.
From my experience, it is best to host such a database online, yet cache it for offline access if possible. The app itself ships with a database copy, that was up-to-date the day you built the app for distribution. Each time the app is started, and maybe once a day in case the app is never quit, it will query a web server for the current "version" of the database. If this version is newer than the one shipped with the app, it tries to downloads a copy of this database to its local cache and then switches to the cached copy for future lookups. If the cached copy gets lost (caches may be flushed by the system at any time), it will have to re-download it. In the meantime, it can use the shipped database, which is outdated, yet better than nothing. If download is not possible (e.g. not enough free space is available on the device), the app may want to make online queries directly if the user currently is online, fall back to the out-dated shipped database if he is offline, and retry to download a cache copy at some later time (maybe the device will have more free space available at that time).
So basically your app will have a work flow as follows:
START
A locally cached copy exists? If NO Goto 6.
The locally cached copy is up-to-date? If NO Goto 5.
Perform the lookup using the local cached copy. Goto 12.
Delete the outdated cached copy. Goto 1.
The shipped database is up-to-date? If NO Goto 8.
Perform the lookup using the shipped database. Goto 12.
Download the updated database.
Download succeeded? If YES Goto 4.
The user is currently online? If NO Goto 7.
Perform the lookup using a JSON webservice. Goto 12.
END
If you only add more entries to the database in the future, yet existing entries will never change, there is also another, even much better option: You have simply two databases. One that ships with the app and one that only contains the updates (new entries added) after the last app release. This shrinks the amount of data that needs to be downloaded and cached dramatically. In that case your app must always perform two lookups, one in the shipped database (which is always performed first), and if nothing is found there, in the downloaded cached copy, which does not contain the entries already found in the shipped database (or directly online, if no cached copy is available, yet the user currently has Internet access). Each time you release a new update of the app, it will get a new full copy of the database, hence you can reset the update database back to zero entries and only keep adding new entries there (or you can keep different update databases lying around on the server for different app versions that had different databases shipped with them, if you don't think that is too much hassle to manage).
The update database for download may even be created dynamically by the server, that would of course be the best option. E.g. after shipping the app, you add 3 vendors and 30 products to the database, and every vendor and product has a unique ID (that is strictly increasing with each new entry added), then the app can tell the server that the highest vendor it knows has ID X and the highest product has ID Y, in which case the server sends out an update database with all vendors and products whose IDs are higher than X and Y.
All these decisions influence on the database format to use. Generally it sounds a lot like a job for CoreData, yet if you want dynamic update databases, the updates should be delivered in a different format (JSON, XML, CVS, or something else a server can easily generate) and be converted to CoreData by the app after the download is completed, since dynamically generating CoreData databases on a server is rather hard and definitely not recommend.

What is the most effective to sync all the data present in my server with the database in my ipad application?

I have a lot of data present in the database present in my webserver. Each time I starts the ipad application after downloadiding, I want all these data to be copied into the sqlite database present in my application. Then using this data, the application should work.
We are now using xml's and sometimes on 3g it takes about 20minutes which is completely unacceptable. After the 1st time it syncs using time log and all. And it works without any problem.
Is there any other way I could get all the data and make it populated into my sqlite db?
If it is a large database it might be worth doingin the background. And even better if it was just over wifi (otherwise you'll be eating up your users data)
What I usually do is have a local copy of the database shipping with the app, so the user can use that, and update it in the background. It might be worth creating some pages where you just present the updated content, download that, then update your database accordingly. Rather than downloading everything all the time.
This would depend entirely on your implementation however.
On initial app launch you could download just enough data to make the app functional. Then download the rest of the data in the background.
This is a common strategy used by Sync Frameworks and works pretty well. I have personally tried with with synchronizing more than a thousand objects using OpenMobster's sync service.
Now what data to download initially is to be decided by the requirements of the App
Thanks

Resources