Multi dimension Lookup Table - ios

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.

Related

Realm sync across the clients

I searched across many threads and issues but I doesn't found the answer.
When I use the Realm Objects Server and the clients connects to the server, the whole DB is synced across all the clients?
In other words, if I have a public DB with millions of objects, relations, etc all the clients have a copy of the whole DB on their devices?
I'll need Realm sync feature but I don't know how to sync occurs. Is the sync incremental? Every user has the objects that device needs to make queries?
My app will increment the size every hour, and the sync feature of the Realm is perfect for me, but I have doubts about the size of DB over the time and how clients sync a lot of data.
Thanks in advance!
At present, yes. Public Realms are synchronized in their entirety to every client's device. The entire list will initially be downloaded when the client's device connects for the first time, and from that point on, any additional changes will be synchronized at the time they are made on the server.
That being said, all Realm files are compacted (ie, all empty allocated space is removed and all strings are condensed), and then compressed with gzip before being downloaded to the client, so as long as the public Realm doesn't contain large binary blobs, even very large files should come down quite quickly.
It's on the roadmap to add partial replication to the Realm Mobile Platform. This will allow only portions of a single Realm file to be synchronized to specific clients. However there are no concrete plans for when this will be released.
For the time being, the easiest thing to do would be to maintain the master list of data on the server, and copy only the desired data to each user's private Realm. However since this would require custom logic to be executed on the server, it would require the Professional or Enterprise editions of the Realm Mobile Platform.

iOS data base architectural decision

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.

Migrating iCloud Core Data manually

I have an app that reads wind readings at sites around the world. I decided to use iCloud and Core Data using a shoe-box style app.
The wind readings update hourly, after a few weeks of using the app I realised this was a bad idea as iCloud/Core Data just fills up with megabytes of transactions and restoring a device takes 10 minutes to download the store to a fresh device.
My solution to this was to use Core Data configurations so that the "sites" were stored in the iCloud store but the hourly changing "wind readings" which get deleted after 12 hours were stored in a local store. If it makes it easier to imagine, it works similar to RSS "sites" and "entries" which change hourly.
This all works great but I can't work out how to write migration code for the 2.0 version of my app. After reading how configurations work I had to remove the parent/child relationship between sites and wind readings and use fetch requests to link them up using a common siteIdentifier UUID.
Doing it this way I assume I cannot use light-weight migrations? Also loading up the versioned .momd model file just gives me the latest model so how do I get hold of the original model file to load up the store and do everything manually.
On the other hand, is this just too complicated and I would be better removing iCloud support or there is another way you'd recommend?
You should be able to use a lightweight migration in this situation.
The reason is, as far as your 'iCloud' configuration is concerned you are just deleting an entity and dropping a properties (i.e. dropping a table and a column). Automatic migration can handle that just fine.
However...
There is a catch. It won't copy the data you have to the 'local' configuration first. Therefore you will need to do that manually before the migration. Here are the basic steps:
Determine if this migration needs to occur.
Copy the sqlite file to "local.sqlite".
Stand up the iCloud configuration, this will delete the readings.
Stand up the local configuration, this will delete the sites.
Test, test, test again, and keep testing.

iOS - how to structure database to conform to iCloud backup rules

I've been having trouble getting an app submitted to the App Store. This is due to the fact that that database, which is updatable, is too large for the iCloud backup limitations. Most of the data in the db is static, but one table records the user's schedule for reviewing words (this is a vocabulary quiz).
As far as I can tell, I have two or three realistic options. The first is to put the whole database into the Library/Cache directory. This should be accepted, because it's not backed up to iCloud. However, there's no guarantee that it will be maintained during app updates, per this entry in "Make App Backups More Efficient" at this url:
http://developer.apple.com/library/IOs/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/PerformanceTuning/PerformanceTuning.html
Files Saved During App Updates
When a user downloads an app update, iTunes installs the update in a new app directory. It then moves the user’s data files from the old installation over to the new app directory before deleting the old installation. Files in the following directories are guaranteed to be preserved during the update process:
<Application_Home>/Documents
<Application_Home>/Library
Although files in other user directories may also be moved over, you should not rely on them being present after an update.
The second option is to put the data into the NSDocuments or NSLibrary directory, as mark it with the skipBackupFlag. However, one problem is this flag doesn't work for iOS 5.0 and previous per this entry in "How do I prevent files from being backed up to iCloud and iTunes?" at
https://developer.apple.com/library/ios/#qa/qa1719/_index.html
Important The new "do not back up" attribute will only be used by iOS 5.0.1 or later. On iOS 5.0 and earlier, applications will need to store their data in <Application_Home>/Library/Caches to avoid having it backed up. Since this attribute is ignored on older systems, you will need to insure your app complies with the iOS Data Storage Guidelines on all versions of iOS that your application supports
This means that even if I use the "skipBackupFlag", I'll still have the problem that the database is getting backed up to the cloud, I think.
So, the third option, which is pretty much of an ugly hack, is to split the database into two. Put the updatable part into the NSLibrary or NSDocuments directory, and leave the rest in application resources. This would have the small, updatable part stored on the cloud, and leave the rest in the app resources directory. The problem is that this splits the db for no good reason, and introduces possible performance issues with having two databases open at once.
So, my question is, is my interpretation of the rules correct? Am I going to have to go with option 3?
p.s. I noticed in my last post cited urls were edited to links without the url showing. How do I do this?
Have you considered using external file references as described in https://developer.apple.com/library/IOS/#releasenotes/DataManagement/RN-CoreData/_index.html . Specifically, refer to "setAllowsExternalBinaryDataStorage:" https://developer.apple.com/library/IOS/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSAttributeDescription_Class/reference.html#//apple_ref/occ/instm/NSAttributeDescription/setAllowsExternalBinaryDataStorage: . Pushing out large data into a separate file can help reduce database size .

Delphi: 30-day trial

How can I make a 30-day trial for my application? I need to allow users to use an application only 30 days. How to count these days?
I keep the first and the last date in registry. But if to change a system time - no protection will be. I need to count these 30 days.
You could probably come up with a system that requires an internet connection, but without something that the user can't tamper with, I don't see a solution.
Any solutions that rely on an untrusted element (an element of the protection that is under the user's control) is critically weak.
The simplest way I can think of to protect against the user moving the clock back is to limit the total number of launches.
However, attempts to limit the number of launches requires persistence -- saving data to the disk, perhaps encrypting and storing a modified version of your activation data file -
Imagine that you count one of the 30 days as "used up" once the app has been launched, on a unique occasion, even when the same date is re-used. In order to avoid using up more than 1 "activation time day" when launched, the user must allow your software to re-save its activation file each time it runs.
To block that approach, the user needs only to keep the apparent date from changing, plus they must either prevent you from storing anything to disk; or they can simply track and record your changes and reverse them out, either using a monitoring process, or using VMWare snapshots. About VMWare snapshots, you can do nothing. The virtual machine's disk is not under your control.
You can protect your app of users setting the clock back simply by storing in the registry the date of last execution.
Each time the app is started you need to do the following:
Check current date (as reported by the system clock) against the stored last execution date and, if current date is earlier than the last execution one, consider that the trial period has expired (or whatever you prefer).
If the previous check is ok, save the current date in the registry and continue execution.
As WarrenP says, any technique storing information locally can be easily circumvented using VMware snapshots.
And anyone, including those who check via internet, can be skipped via assembler level hacking.
Here's a discussion on Shareware trial enforcement with Delphi:
Best Shareware lock for Delphi Win32
Along with discussions on various 3rd-party solutions, techniques for DIY, etc..
IMO, DIY is feasible if your app produces data that the user will want to keep around, then you can simply embed a copy of the usage/day counter in the database in such a way that they can't wipe it without destroying their data. I also like watermarking (printing "trial" on reports, etc..), escalating nag severity, but I do not recommend or condone "drop-dead" crippling until WAY past the expiration data. I also like to measure "days of actual use", instead of using a calendar.
Registry manipulation works, and many of the 3rd-party protectors use it. But you need to be stealthy, and keep backups in several locations simultaneously.
You should also consider having separate trial and registered versions. But also consider that pirates will buy the registered version with a stolen card, and put it on Rapidshare, BitTorrent, etc..
Also note that elaborate defenses lead to support headaches. Sometimes PCs crash and the clock gets set backwards. They install new harware. PCs get rebuilt, restored from backup, etc.. If a user is running a debugger, he may be a software developer, not a pirate. If your app looks like it has been patched, it may be an overly-aggressive antivirus. And at any time, a shoddy patch for Windows may cause your program to think that it's being attacked, hacked, or reverse-engineered. You have been warned...
Encrypt a date and store it in registry the best way to do it is that date to be stored by the installer itself and if the date doesn't exist the application should quit.
There is an open source project (which was a commercial product before):
TurboPower OnGuard is a library to create demo versions of your Borland Delphi & C++Builder applications. Create demo versions that are time-limited, feature-limited, limited to a certain number of uses, or limited to a certain # of concurrent network users.
I have not checked which Delphi versions are supported.
For this kind of "protection" and some others, I have used TmxProtector (open source) from MaxComponents in the past with good results. From the link provided:
The TmxProtector is a software protection component. It was designed
for quick implementation of application protection functions. You can
create time-trial and password protected applications. You can set the
maximum number of execution, and it can work with registration keys as
well.
This compoment uses very simple encryption to store the expiration date in the registry and it provides some simple detection for tampering on the system date.
It sounds like you need to store the date the last registry entry was written. Then inside your program, test if the current date is less than the date last registry entry was made. If true display a message that the trial period has expired and the program must be purchased.
Here are some ideas on how to deal with clock changes during the trial period:
Save both the date of first and the date of the last program start. If the date of the last program start is greater than the current date, then the user has moved the clock back. I simply increase a day and save the new date as the date of last start. You can of course decide to just end the trial.
To try to defeat trial bypass programs (RunAsDate for example) which run your application by setting the date and time to a specific value, you can instead of getting the date via the usual Delphi way (Date, Now), get, for example, the last modification date of NTUSER.DAT.
Save your trial data on two separate locations, either two registry locations, or file and registry. This way even if the user deletes one of the trial data locations, you'll still have a backup one to use.
If you keep your trial info in registry, the registry could be deleted by the user. Evey one expects to find the registration info there.
There is one place where the user might not think to look into: your own app (EXE file). Put an ANSI string constant (MUST by ansi/ascii or other 1 byte string, static array, etc) into your program, like 'xyxyxyxyxyxy'. Compile your app. Open your complied app with a hex editor. Search for that string. Now your program could use that area to store the trial info into itself.
Use this method in conjunction with others: store your info in registry also, on disk, etc.
Anyway, the best would be to get the registration info from your server.
The big drawback: 1. The server must be ALWAYS online! 2. The user must be connected to internet (when it uses your app).
Also use a Delphi license management library to help you encrypt the license info and generate a string-based key that you can send to your customers upon registration.
Anyway, whatever you send to your server needs to be based on the hardware fingerprint of that computer. Otherwise your license key will leak out on some warez website and everyone will be able to use that key. But if the key is hardware-based it would be useless if it is leaked on Internet.
Just remember: don't over do it! There is no such thing as unbreakable software protection. Microsoft could not do it!
As the thread pointed to mentioned, I encourage you to look into WinLicense: http://www.oreans.com.
I've been using it for quite some time and it handles trial periods quite well. It also handles licensing, customer lists, etc.
Tom

Resources