In my spritekit app, I have Chapters which contain 30 levels. All of the levels are initially locked. Once a level is won, the next level is unlocked. NSUserDefaults does not seem like an ideal choice. I tried to save my data in a plist file in the "application support" folder by having an array for each level pack and a value (1 or 0 depending on the level's status) that corresponds to each level. This also did not seem ideal because it could be edited and would be reset with an update.
My goal is to have this data persist through an app Update and not be easily edited by a user. Are there any good solutions for this?
NSUserDefaults is a actually a very good way to store data like this. You are after all only talking about storing BOOL values. NSUserDefaults is not reset or deleted during an app update unless the user deletes the app. This is stated in the iPhone iOS Programming Guide, Files Saved During Update (page 114):
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.
As Whirlwind already commented, there are many ways to store data. Here is a link to a previous question dealing with various storage methods.
You can serialize your property list and store it as data into the NSUserDefaults. You can also encrypt it before storing, to ensure nobody can modify it in any way.
Apple Docs for plist serialization
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/PropertyLists/SerializePlist/SerializePlist.html
Related
The app I'm working on generally uses a single SQL store in Core Data to hold a working dataset for the app. However, there can be any number of small, separate stores which originated as either
In-app Purchased content, or
Exported subsets of the working dataset that may be reused from time to time.
These will always consist of a single sqlite file (WAL turned off). The In-App purchases can always be re-downloaded, but it would be possible for the exported data to be lost for good (since they might choose to permanently delete the data after it is exported).
Intuitively, since the exported data might not be possible to recreate, it should go in a subdirectory of the documents folder. But I'm not sure whether Apple would agree about that.
I have no idea where the downloaded purchased content should be saved, since technically, it can be re-downloaded at any time.
So, my question is, where in the iOS filesystem should I put these (iOS7 and beyond).
There is no official, public guidance on where content purchased via IAP should go on the filesystem. However, experience with Data Storage Guidelines feedback has indicated that:
NSDocumentsDirectory should only contain data created or edited by the user
(some) Non-user data can still be stored in NSDocumentsDirectory if it has the NSURLIsExcludedFromBackupKey attribute set. In general you should still try and avoid doing this.
In-App Purchase content is considered "restorable application data" and should be stored accordingly. The application support directory is one place where it could be stored.
If your exported data was exported by a user-initiated action and the data at that point "belongs" to the user, storing that exported data in the NSDocumentsDirectory should be fine. If you have any doubt, store it in the application support directory or caches directory. Be aware that in low space conditions the data may be purged by the system.
I have a CoreData app (using https://github.com/lhunath/UbiquityStoreManager), backed by iCloud. In one use case a user with a local store enables iCloud (where data already exists). I want to prompt the user to make a decision of whether to migrate the local data to iCloud or just use the iCloud version. As part of this, I'd like to display the device name and last sync date of the version in iCloud.
I've been tinkering around with my NSPersistentStore's metadata, but that doesn't appear to get synced to iCloud.
Any suggestions?
You could use iCloud's key-value store to store the device name & date of the last sync.
My no doubt unpopular suggestion is "don't". Trying to determine what is in iCloud at any given time puts you on pretty shaky ground. You may be able to get it to work most of the time, but there will always be circumstances where it breaks down.
If you really must import some data when first enabling iCloud, I suggest just always importing the data, and then deduping later as the iCloud data comes in. As ugly as it sounds, that's the only approach really guaranteed to work with Apple's approach.
It is worth taking a look at other Core Data sync frameworks like TICDS and Ensembles. They take a more sane approach to data identity, which means you can avoid the whole deduping step. (Disclosure: I develop Ensembles)
do a metadata query on the iCloud files and check the most recent transaction log file in iCloud. See the link below for a sample app that uses this approach to check whether the app is properly synchronised with iCloud.
http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/
EDIT:
I just realised I don't get the actual device name, but once you have found the most recent log file then use this to get the device. Just be aware this call may be expensive.
NSFileVersion *openedVersion = [NSFileVersion currentVersionOfItemAtURL:fileURL];
return openedVersion.localizedNameOfSavingComputer;
What happens to the app when it is killed/terminated from the multitasking tray (i.e double click the home button and delete it from there)? And i relaunch the app again by clicking on it? Consider this scenario. I save some variables (global variables) and i save some values to them. I killed/deleted the app from multitasking tray and relaunched it. I no longer have variable values. How can i store them through the entire process of app life cycle and they can be changed when someone changes within the app life cycle. If you need more information please ask. I have been saving the values to a plist file.I created a settings bundle and saving values to them as global variables..is it the way to go?
To save data even after the app is killed/terminated, you have to use persistent storage. There are a number of different ways to do this. A few of these ways are using NSUserDefaults, plists, or CoreData.
See these links, and try to find out what's best for what you're trying to do.
iOS persistent storage strategy
Use SQLite, plist, or something else?
You should also check out the iOS development lectures, there's two parts and the first part covers persistent storage in great detail. It's called Effective iPhone App Development. I recommend watching both, but the first part of the first one would answer your questions.
https://developer.apple.com/videos/ios/
My game uses cocos2d-x and will be published on iOS platform first, later on Android. I save a lot of things with CCUserDefault (scores, which level was completed, number of coins taken, etc...). But now i have a big doubt.
What will happen when the game will receive its first update?
CCUserDefault uses an xml file stored somewhere in the app storage space. This file is created and retained until one uninstall the app. I am wondering what happens when the app is updated. Will the old xml file mantained?
Because if not, how should i handle app updates (updates in the sense that 2,3 or more new level packages will be added, but the informations about the old ones, like scores, which level was finished and which not, number of coins etc..., need absolutely not to be lost)?
Thanks.
As much I know normally they not reset on update, you need to delete the app. What I think what you need at your first/previous update that you make some setting which signify/tell about version and if it not equal to recent one than update your NSUserDefualt with some basic setting or say reset your setting.
Ok, i found the answer. CCUserDefault stores the xml file under:
application_home/library/caches
The iOS App Programming Guide states that all the data under
application_home/document
application_home/library
will be preserved. That is, after the update, your userdefault.xml file will be still there.
My app was recently rejected from the app store for storing data in the Documents directory. I had moved it there because with the latest change, the db must now be writeable - it's no longer read-only.
In researching the solution, I've read that it's actually preferable to use NSLibraryDirectory. Is this so, and more importantly, will that address Apple's concerns? Their complaint is that the app lets the user download to much content (it doesn't let the user download any unless you count the db), and that it's storing "too much data" in the "incorrect location." The data is 8 mb, but could grow to about 10 or 12 mb max.
Actually its because of iCloud.
using iCloud, Application's document directory is synced to cloud and to other devices and hence Apple want developers to store only that data in document directory which they want to sync with iCloud.
I came to know this form one of my friends who work # Apple California and I'm not really sure if this material is on Apple's documentation.
I had this issue with an update to a suite of apps I develop the other week. The funny thing was that only five of the seven apps (exactly the same code base) were rejected.
I believe the issue in my case was duplicating assets from the .app bundle into ~/Documents.
My first attempt to comply with their new storage guidelines was to implement the do not backup switch on the files I was copying into ~/Documents. No deal with that so I had to change my implementation to not copy the data at all. The apps were promptly approved.
Your implementation is probably different but in my experience Apple no longer likes you copying things from the app bundle into ~/Documents, as it could be duplicating data unnecessarily (in their view).
They suggest copying into ~/Caches (or whatever it is), but this can be cleared in low storage situations and may not be right for your case either.
Hope that helps.
A product I wrote a year ago uses CoreData (with a SQLite data store). This database file is stored in ~/Library/Application Support//. This was approved by Apple without issue.
"Application Support" does not exist in ~/Library, so you will need to create it.
Documents is not a great place to store your database file for several reasons. Apple has their reasons, since they rejected your app. Another reason is that the Documents directory is accessible by the user (via iTunes), and unless the user deleting your database file is no big deal to the operation of your app, it is best to put it where they can not do anything with it directly and/or inadvertently.
You can still put those files in the Documents folder, you just have to give them an attribute that lets the file system know not to back them up to the iCloud
This is a great example of how to do so on different iOS versions