iPhone user history database (SQLite? Core-Data?) - iphone

In my iPhone app the user can choose from a large list of audio on demand programs available on a website, sorted by speakers, programs names and days of the week.
I'd like the app to have a history of the most recent heard programs, so the user can keep track of what he has already listened to, including the date and time of accesses.
When the user is in the final stage of his choices I have three resulting NSStrings available in memory:
NSString *program;
NSString *speakerName;
NSString *weekDay;
How can I build a database, a history access, storing these 3 strings (plus date, time and how many minutes the audio has been played) every time the user listens to a different audio file so he can have a list of his played programs?
I'm reading about SQLite and Core Data for the iPhone but I'm not certain if that's the way to go, since I'll have just a few elements to save each time on a database.
Does anyone know of a sample xCode project for doing that? What should I study to accomplish this task?
Any suggestions/guidelines will be greatly appreciated. Thanks!

For something this simple, you should use NSUserDefaults.
Basically, NSUserDefaults gives you a dictionary into which you can put NSStrings, NSDates, NSNumbers, or NSDictionarys or NSArrays of these objects. To use it you do something like
[[NSUserDefaults standardUserDefaults] setValue:myString forKey:#"myKey"];
Then later, you can access the value by doing:
[[NSUserDefaults standardUserDefaults] valueForKey:#"myKey"];

Related

How to offer non-consumable content for in app purchase?

I am developing an app for learning piano and I would like to offer lessons as non-consumable in app purchases. All of the files that are required for the lesson will be bundled with the app (as they don't take up a ton or space; two PDFs, a .mid, and a .png). Currently, for testing purposes, I have just been hard coding the lessons into my app and they get loaded on viewDidLoad.
My question is how can I store a library of lessons that I can modify when a purchase is made to show that it had been purchased? Essentially, all I want to do is when a completed transaction is received, the value of purchaseStatus will change from 0 to 1.
The stored data consists of a number of strings, NSNumbers, and an array of NSNumbers.
I have seen a few options such as plists and NSUserDefaults but I'd really appreciate some advice on the best way to go about it.
Thanks in advance :)
I would say storing the purchase status of each purchasable module in an NSDictionary that you store in NSUserDefaults would probably be the most straightforward/simplest option. Every time you launch the app, query this dictionary to determine what has been purchased and accordingly reveal those purchased entities to the user (in the form of an entry in a table view, an icon, a no longer hidden button, etc.).
Plists are fair game as well, but it would require a bit more maintenance (where to store the plist so that it may be backed up by iCloud, etc.) whereas NSUserDefaults has that all taken care of for you (it's backed up by iCloud).

Saving player's data from iPhone to iPhone

I have an iPhone game, where, dunno, the player has like 3000 gold. Sweet.
Then his iPhone had some badass spontaneous combustion.
The player gets a new iPhone, but logically the game will reset him to 0 gold.
What method do you recommend me for saving such important data? Also, the data I might want to store can be a bit larger (loads of arrays containing important player stuff).
Thank you.
Store the info you need in the application support directory for your app.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *appSupportDirectory = [paths objectAtIndex:0];
You can write your arrays out to a plist file in this directory. Then if they choose to restore from a backup from the destroyed phone and they have made sure to sync their phone before they let it combust they will get their gold back.
Keep in mind that one could use the restore from backup feature to get to a previous amount of gold so you want to store their purchases and progress in a similar manor.
Also, depending on what you mean by "loads of arrays" you should probably consider using core data instead of plist files. Your code will scale much better. You can store your database in the same directory to get the same backup behavior.
Recently some apps tried to provide an option to sync data with dropbox. There must be some easy code snippets to do that. You could give an option to sync the save game data with Dropbox.
You can use GameCenter or OpenFeint or both. In fact, most devs use both.

How easy is it to hack a plist file in an app store app?

Don't worry, I'm not trying to hack someone else's app, if that's what you're thinking =).
I want to have 2 versions of my app, a free version and a deluxe version. My plan was to use an in-app purchase to enable the deluxe version by setting a boolean value in the plist file.
My question is: is this secure or is it easily circumvented? And if it is not secure, can someone suggest a simple alternative? I don't want to download additional content, I would rather keep all of the functionality within the app and enable it somehow.
Edit: I don't mean the application plist file, but something like the user defaults file.
You should store this in the keychain, this is what I'll do. The keychain is far more secure than a .plist or the user defaults (which are .plists, too, as far as I know). Have a look at SFHFKeychainUtils, you should be able to use this or just implement a better method exactly for the need to save a simple bool.
It is easy to edit the com.something.plist without jailbreaking. With a free tool* you can browse your device, you can also edit and save these files. If you store your inapp purchase something like this:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"com.example.pack1"];
[[NSUserDefaults standardUserDefaults] synchronize];
then this will be written to the plist:
<key>com.example.pack1</key>
<true/>
If you name your packages like this: pack1, pack2 etc., and somebody edits your plist (copy/pasting the first key), he/she could use the locked feature easily.
A not too hard to implement method would be to save like this:
[[NSUserDefaults standardUserDefaults] setValue:[self sha1ValueForKey:#"com.example.pack1"]
forKey:#"com.example.pack1"];
[[NSUserDefaults standardUserDefaults] synchronize];
where -sha1ValueForKey: is
-(NSString *)sha1ValueForKey:(NSString *)key {
return [self sha1:[NSString stringWithFormat:#"<SALT>%#", key]];
}
You have to change <SALT> to something.
You can find -sha1: here: http://www.makebetterthings.com/iphone/how-to-get-md5-and-sha1-in-objective-c-ios-sdk/
After this you can verify if the key matches the hashed value.
If somebody wants to hack your plist he/she has to know your hashing mechanism and salt.
This is not the safest way to protect your application but it is easy to implement.
*iExplorer
EDIT:
The suggested method only protects - somewhat - your IAP if the user doesn't have access to the hashed value. If someone gets it from somewhere, it is easy to copy that data to the plist. If the SALT is device dependent copying is useless.
I would recommend reading up on verifying in-app purchases. It sounds to me like you are trying to roll your own in-app purchase verification system which may be wrought with issues you might not have thought of yet. You have to be careful with your user's purchases that they will behave the same in your application as they will in any other, lest ye lose their trust (and future sales!)
Instead of worrying about the Info.plist file, why not just set a preference? Somewhere in your code, this would give you your boolean value:
[[NSUserDefaults standardUserDefaults] boolForKey:#"someKey"];
If the value doesn't exist, the result will be nil. This code sets the value:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"someKey"];
Plus, these values will be backed up in iTunes, so if the user moves their backup to a new iPhone or simply restores from backup, the values will be restored.
I don't have an answer, but it seems that editing your plist file dynamically is not possible, if I trust this subject :
You can not edit you're info.plist
file dynamically. When you submit your
app to The App Store, your app bundle,
which includes info.plist, can't
change because the signature created
when you compile you app is based on
the bundle.
Any pirate has a jail-broken iPhone
Any jail-broken device offers full file system access via tools like PhoneDisk, etc
Any file system access allows people to change the values in your applications .plist file
Game over.
Now, its not trivial to wrapper that up for the script kiddies but then again its not that hard either.
Storing state in defaults is no more nor less safe from privacy than having two versions of your app. Pirates will either pirate the deluxe version, or they'll pirate the unified version with the flag set.

Best way to store a string in an iPhone app?

I've started a new iPhone app that needs to remember a single, 40-char string. That's it. I've hooked into Core Data, and am reading about it now, but it really seems like overkill. Is there an easier way to do something so simple?
NSUserDefaults would probably be the easiest way
// To Save
[[NSUserDefaults standardUserDefaults] setString:myString forKey:kMyStringKey];
//To Load
NSString * myString = [[NSUserDefaults standardUserDefaults] stringForKey:kMyStringKey];
This will persistence between sessions.
Edit: This is assuming of course that the string is not constant for everyone using the program. If it is you can just hard code it. This is for if every instance of the app needs a different string, but you want the string saved between runs of the app.

How do I save my iPhone application data without a server?

Is there any way to save data without connecting to server on the iPhone? If so, please describe how.
Look at the NSUserDefaults class. It can save primitives and NSArray objects of primitives.
Example, your app might write out before app terminates in your app delegate:
[[NSUserDefaults standardUserDefaults] setString:#"Value" forKey:#"Key"];
And then read it in after launch:
NSString *dataYouNeed = [[NSUserDefaults standardUserDefaults] stringForKey:#"Key"];
Just remember to handle the nil case gracefully (i.e. that the app will keep working immediately after a fresh install or a reset to the user defaults).
Edit: the question has already been more-or-less rewritten. Obviously if you need to store data that will act as your application's model (in the MVC sense), Core Data or sqlite is where you would do best to start looking.
If it's a small number of things, use NSUserDefaults. If it's a lot of stuff, use Core Data.