FInd Out if User Switched off Document and Data From iCloud Account - iphone

Once again stuck in iCloud :(. I am using Core Data + iCloud and in my app i want to know if user switched off Document and Data from his account.
Thanks

There is no built-in support for detecting this change, only for detecting if the user has logged out. One common approach is to write a sentinel file to iCloud, separately from Core Data, and then monitor that file to see if it disappears. Details vary but it's usually something like:
Write the file using NSFileManager iCloud calls, and store the file name in user defaults. Each device using the account will have a different file, so including a UUID in the file name is a good idea. You only write this file, you never change it.
Use either NSFilePresenter or NSMetadataQuery to get notified of changes to that file-- like, if it disappears.
If the file disappears, take immediate steps to unload the entire Core Data stack, including every managed object, because they don't have a persistent store backing them up any more.
One sample implementation is in Black Pixel's version of the Core Data "Recipes" demo app. You might need to tweak it to get it to work right in your code.

There are two cases:
The app is not running, or in the background when the account status changes.
The solution here is to store / compare the identity token using NSUserDefaults (or some other storage local to the app). Grab the identity token from NSFileManager and compare it to the cached value each time the app finishes launching or comes back to the foreground.
id token = [[NSFileManager defaultManager] ubiquityIdentityToken];
The app is running when the account changes.
This requires a file presenter to "something" inside the container. The best solution is to use a file that is not synced.
Implement -accommodatePresentedItemDeletionWithCompletionHandler: to spawn a thread (dispatch_async works great) and do your cleanup work.

Related

How to sync Core Data with referenced files?

Just started to read various posts how to sync files or core data using iCloud. The app I'm currently developing stores data inside core data and filenames as references to the image files stored in documents app sandbox. So, a related file (photo) is also created in documents dir every time a user makes a record inside a database.
Everything looks fine if we would need to sync files OR core data, however I'm looking a way how to sync core data AND files. So, I'm worried about the case if new core data records will arrive earlier than image files of those records. In that case, data integrity will be broken. Actually, I would prefer all new related files would come first, and then all core data updates. Is it possible to do that?
Not really, no. You send data to the cloud, but you have no way to control when it appears on other devices. iCloud is going to bring over your managed objects whenever it feels like it, regardless of the state of the external files. The only way you could make this happen would be to find and download any external files, wait for the download to finish, and only then bring up your Core Data stack. But that would mean locking the user out of the data store until the downloads finish, which is not a good idea.
When I faced a similar situation, I handled it like this:
Initiate downloads of all the external files and bring up the Core Data stack.
Modify the getter method for the image to check whether the file exists and has been downloaded.
If yes to both, proceed normally
If no, display a "loading..." UI element. This could be a spinner or a progress indicator. Listen for a custom "download complete" notification.
Whenever an external file finishes downloading, post that "download complete" notification. Re-check the file, and if it's ready, replace the "loading..." UI with the image.

Whatever happens to iOS Application's data persistence when the App gets deleted?

I want to keep some of the critical(and less memory consuming) data of my App(ex: licence key or user credentials), stored in the device. In normal scenario, when the user deletes the App from the device, all the data related to the particular App gets deleted.
But I would like to override this behavior, and store some important stuff inside the device's disk, so that it does not get deleted along with the App. How to do that? Any help is much appreciated.
you can always store the license key and user credentials in the ios keychain.. it will stay there even if you delete the app. You can use the SSKeyChain API to access the key chain. Keep in mind you can only trivial string info this way.
Hopefully for obvious reasons that isn't possible. (What if every app did that? They you'd delete every app on your device and still find that gigabytes of space were being taken up by "deleted" apps.)
No, if you want data to be saved even after deletion, you'd need to store it in "the cloud" somewhere.

Retro-fitting my app for iCloud

I have been puzzling about retrofitting my app for iCloud for a few days and hope someone can help. After getting past code signing issues I am not sure I understand the model for incorporating iCloud. I'll tell you the problem I'm trying to solve first since I'm a big believer in telling people what I'm trying to do before having them try to fix the way I'm doing it :-)
My app workflow
User browses the store which lists a series of training plans they can download
User picks a plan and downloads it
I pull the training plan from our webserver customized to their needs
I add the filename for the training plan they downloaded to a plist of plans they own
User opens the training plan and sees the day-to-day schedule
I want the user to be able to do this on their iPhone and then open their iPad and see the exact same training plans synced over there.
My problem
I currently save the files to the Documents directory and that works just fine. How do I retrofit this to work with iCloud such that folks without iCloud enabled can continue to use the app but those who do get the added benefit?
My understanding
I'm confused as to whether I still need to save to Documents folder and then save a copy to the iCloud folder OR whether I just write to the iCloud folder from now on.
If it's the former I believe I just write a copy the Documents folder files to the iCloud area too to push it up but how do I detect a new file in the iCloud folder and copy it back to my Documents folder?
If it's the latter the files should just exist right?
I'm hoping it's the latter and that still supports devices without iCloud turned on...
Thanks for any help clarifying.
Adam
The iCloud API is pretty well documented and there is a specific chapter that deals with what you are after:
Managing the Life Cycle of a Document
A document goes through a typical life cycle. A document-based
application is responsible for managing its progress through that
cycle. As you can see from the following list, most of these
life-cycle events are initiated by the user:
The user first creates a document.
The user opens an existing document and the application displays it in the document’s view or views.
The user edits the document. A user may ask to put a document in iCloud storage or may request the removal of a document from iCloud storage.
During editing, saving, or other actions, errors or conflicts can happen; the application should learn about these errors and conflicts and either attempt to handle them or inform the user.
The user closes a selected document. The user deletes an existing document. The following sections discuss the procedures a document-based application must complete for these life-cycle operations.
In essence, you application is responsible for working out whether iCloud is available for a particular user and then confirm that the user wants to store their data in the cloud. Based on that selection you will need to work out how to move their existing data from the documents directory to a cloud URL.
On other devices that are setup to use iCloud storage, you have the option to discover documents available via a metadata query.
http://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/DocumentBasedAppPGiOS/ManageDocumentLifeCycle/ManageDocumentLifeCycle.html#//apple_ref/doc/uid/TP40011149-CH4-SW1
If you are looking for a very easy sample which implements iCloud, have a look at this:
iCloud basics and code sample
This gives you a concrete example of how to implement some of the stages Rog has cited in his post above. Hope this helps.

Recreating core data at application launch

I have an app that connects to a website. I store its data as core data and then I use the core data to load my tableviews. I believe, I want to reload the data from the website every time I launch the app, since the user could change the data if they were to go onto the website.
What's the best way to approach this? Should I just delete the core data each time the app terminates?
It depends on how critical it is that data on the device always be current, on how long you expect users to wait before working with the app, and on what you want to happen if someone tries to use the app when the network is slow or unavailable. If you delete the store, and the app can't connect immediately, the user has no data. Even if the network is fine, the user still has to wait on network and server latency before they can start using the app. This is likely to be poor UX.
On the other hand if you allow data to persist after the app exits, the user's data might not be current, at least not at first.
If you don't ever want the data to persist after the app exits, an in-memory store might be the best choice, because it will never be saved to a file anyway.
If presenting potentially old data is OK either (a) briefly when the app starts up or (b) when the network is unavailable, a better choice would be to keep the data store but make new network calls to update the existing data. You could provide some sort of UI to indicate that updates are in progress. You might also have some in-app indication of when your app last synced with the server.
I'm not sure of how your application makes use of the Core Data stack, but if you don't care about (or don't have) changes made locally on the device, I'd say the easiest way to refresh the data from the server is just what you said: wipe out the store file, re-create it and import the data from the server. However, I wouldn't do this systematically on each application launch. Make sure the user knows about it and think of providing a "refresh" button to trigger that procedure. Also make sure you can download new content from the server, before wiping out the local store.
If you want to load all the data in memory (and also want to do updates) then you can create a managed object context backed by a NSAtomicStore persistent store subclass. In the NSAtomicStore subclass you can implement the read: (load: method) and the CRUD actions (newReferenceObjectForManagedObject:, save: and updateCacheNode:fromManagedObject: methods)

How to use a pre-populated database on a coredata context

this is my first question here.
Well, I am developing an iPhone application that will use coredata, but the theres not going to be an option to insert data into the database of the app.
I want to know how to pre-populate it's database.
I thought of creating a plist with all the info and make a function to put it all into the coredata database if the database is not set yet...
but I want to know if it is the right way to do so.
Thanks all.
The easiest way is to create a desktop application with the same model (the exact same model even, just link it in). Then have Interface Builder create you a default UI for it and enter the data. Far easier than doing it on a device.
Once you have the data then include the SQLite file in your bundle and since your app is read only as you claimed; point the NSPersistentStoreCoordinator at the file in your app bundle and Bob's your uncle.
Creating an app on the desktop takes about 5 minutes and will save you far more time on the data entry side.
You can pre-create the database file (sqlite file) using your device and put that in the bundle when you distribute it. When you run the app for the first time you can move that from your applications bundle you can move it to the documents directory where core data will read it.
You can also have a function that runs at the start of your applications first run where it reads from your plist and creates the appropriate objects.