Another challenge when using Core Data and iCloud is knowing when to enable the user interface. Some apps are not simply going to work well if the user is able to do things before the most current data has been imported from iCloud.
To address this issue we are going to illustrate how to disable the UI until the initial iCloud data has been imported. Here we are assuming a scenario where:
- the user has been using the app on a device and has just made it available via iCloud by turning on the Use iCloud option in the Settings app
- they are launching the app on a new device for the first time and your app needs to download the data before letting the user perform any actions
The video below shows how the app will behave when opening an iCloud file the first time.
The following is the sequence of logic we use:
- Launch app and in
- (BOOL)application:didFinishLaunchingWithOptions:
- Call the
OSDocumentManager checkUserICloudPreferenceAndSetupIfNecessary
method which results in an instance ofOSDocumentManager
being created - This will scan for new files in iCloud and create the local store into which the transaction logs will be imported. Transaction logs will not be imported until the app opens the file. For library style apps you would usually do this automatically, for document based apps the user would select a file to open
- Create the
FileListViewController
and push this onto the stack
- Call the
- When the user selects a file from the FileListViewController the
OSDocumentManager createNewFile
method is called- In this method we set the flag
_fileIsOpen = NO
which is checked when receiving notifications to prevent us from responding to notifications we get before the file is opened - Register for
storesWillChange:
,storesDidChange:
andstoresDidImport:
notifications - Open the local UIManagedDocument with iCloud options and in the open or save completion handler set
_fileIsOpen = YES
- In this method we set the flag
- In
- (void)storesDidChange:
- If
(_fileIsOpen == NO)
do nothing because we ignore any earlier Core Data notifications - If
(_fileIsOpen == YES)
then post aNSNotification (@"UpdateUI")
to tell all views to refresh their displays.
- If
- In
- (void)storesDidImport:
we post aNSNotification (@"UpdateUI")
to tell all views to refresh their displays again. We use a timer on this to prevent many messages from being posted because the initial load can result in frequent messages being posted (thanks Tom Harrington)
In parallel to this the initial UIView
will have been displayed and registers for @“UpdateUI”
notifications and by default it should be disabled. When we receive a @“UpdateUI”
notification in the view controller we check for the presence of seed data in the Core Data store by performing a fetch once . If this returns empty we do nothing, if this returns the expected seed data then enable the view. We do this using the following approach:
- In the
- (void)viewDidLoad
method we set_isLoaded = NO
- In the
- (void)viewWillAppear:
method we try and load data and if we find data we set_isLoaded = YES
- In the
NSNotification (@"UpdateUI")
handler of theUIView
we we try and load data and if we find data we set_isLoaded = YES
and we update the UI
When we are updating the UI we check to see if _isLoaded == YES
and if so we display data otherwise we display an activity indicator and message indicating the app is busy loading data.