When to Enable the User Interface

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 of OSDocumentManager 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
  • 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: and storesDidImport: notifications
    • Open the local UIManagedDocument with iCloud options and in the open or save completion handler set _fileIsOpen = YES
  • In - (void)storesDidChange:
    • If (_fileIsOpen == NO) do nothing because we ignore any earlier Core Data notifications
    • If (_fileIsOpen == YES) then post a NSNotification (@"UpdateUI") to tell all views to refresh their displays.
  • In - (void)storesDidImport: we post a NSNotification (@"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 the UIView 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s