11

Swift 1.2 Xcode 6

Long-time listener, first-time caller.

Hello,

Straight from the horse's mouth: "To handle changes in iCloud availability, register to receive the NSUbiquityIdentityDidChangeNotification notification."

Here is the code they provide to implement this:

[[NSNotificationCenter defaultCenter]

addObserver: self

   selector: @selector (iCloudAccountAvailabilityChanged:)

       name: NSUbiquityIdentityDidChangeNotification

     object: nil];

I Swiftified it in my app to:

var observer = NSNotificationCenter.defaultCenter().addObserverForName
(NSUbiquityIdentityDidChangeNotification, object: nil, queue: NSOperationQueue.mainQueue()
){...completion block...}

src: https://developer.apple.com/library/ios/documentation/General/Conceptual/iCloudDesignGuide/Chapters/iCloudFundametals.html#//apple_ref/doc/uid/TP40012094-CH6-SW6

What is the correct way to implement this? Does it go in the AppDelegate? Do we remove the observer when the app gets sent to the background?

The problem I'm encountering is that when the Ubiquity Token changes, the app is terminated anyway because the user has changed iCloud settings.

How do you all manage to subscribe to this notification, and, if you don't, what do you do instead to keep track of the current logged in iCloud user?

Thank you!

4 Answers4

13

Short Answer

To be notified in iOS when a user logs in or out of iCloud while using your app, use CKAccountChangedNotification, not NSUbiquityIdentityChanged.

Long Answer

I've been trying to get this to work as well. I remembered something from one of the talks at WWDC16 that there was something like this that they recommended to use. However, from the sample code they provide, I've only been able to find NSUbiquityKeyIdentityChanged, which I haven't been able to get to work.

So I went back to the video (it's from 2015). That's where I saw them refer to CKAccountChangedNotification – and it works exactly as expected:

  • Launch your app on the simulator from Xcode
  • Exit to the Settings app on the simulator
  • Log in (or out) of iCloud account
  • Go back into your app (tap icon on simulator home screen)
    • A notification is received.
  • Exit to Settings app again
  • Log back out (or in) to iCloud account
  • Go back into your app again
    • Another notification is received.
Anthony C
  • 1,990
  • 3
  • 23
  • 40
  • 3
    Thank you for this. There are so many resources pointing to the NSUbiquity notification, and not enough pointing to this. **Anyone using CloudKit should use CKAccountChangedNotification.** – breakingobstacles Sep 12 '16 at 03:27
  • So, iOS sends the notification when the app returns to the foreground? – Nicolas Miari Dec 20 '16 at 07:02
  • @NicolasMiari Yes, for me I don't get the `CKAccountChangedNotification` until my app goes back to the foreground. – Coder1224 Jan 23 '17 at 03:19
  • So once you get the `CKAccountChanged` notification, do you still check `FileManager.default.ubiquityIdentityToken` to see if iCloud is available or not? Or is there newer synchronous way to check? – Clifton Labrum Sep 30 '18 at 05:09
  • I have tried this solution, but the Selector method is not being called before the App terminates. I have tried both using this and `NSUbiquityIdentityDidChange` to observe changes to when the user turns iCloud support on/off for my app. It seems there's no graceful way to handle this... – Jav Solo Oct 05 '21 at 19:23
1

In Swift 3.0 there was another renaming:

Now the NSUbiquityIdentityDidChangeNotification has changed into NSNotification.Name.NSUbiquityIdentityDidChange.

So the full registering is the following:

// Register for iCloud availability changes
NotificationCenter.default.addObserver(self, selector: #selector(...), name: NSNotification.Name.NSUbiquityIdentityDidChange, object: nil)
LukeSideWalker
  • 7,399
  • 2
  • 37
  • 45
1

On iOS 10 I found that NSUbiquityIdentityDidChangeNotification was never sent. Provided I had a CKContainer (as per the docs), CKAccountChangedNotification was sent in very limited circumstances.

Built with xCode 9.1 then tested on iOS 10.02 iPhone 6+ and iOS 11.0.3 iPhone SE

CKAccountChangedNotification was sent if

  • User logged into iCloud account, or
  • User enabled iCloud Drive in iOS 11. This always resulted in iCloud Drive->App being enabled. However, fetching the account status afterwards yielded NoAccount!
  • User enabled iCloud Drive in iOS 10. The subsequent state of iCloud Drive->App was whatever it was when I disabled iCloud Drive. The account status was appropriate. However, if iCloud Drive->App was disabled at this point, enabling it did not produce a termination or a notification.

Application was terminated if

  • User logged out of iCloud regardless of iCloud Drive status
  • User disabled iCloud Drive->App
  • User disabled iCloud Drive (even if iCloud Drive->App already disabled)
  • User started the app with iCloud Drive enabled, then enabled iCloud Drive->App
Airsource Ltd
  • 32,379
  • 13
  • 71
  • 75
0

I found the same issues, see this question for my comments.

To summarize: On iOS I think apps are killed anyway when the iCloud account changes (or is just signed off). So no need to listen to NSUbiquityIdentityDidChangeNotification.

If you are on tvOS, however, your app is not killed. When your app becomes active, you do receive one or more NSUbiquitousKeyValueStoreDidChangeExternallyNotification with NSUbiquitousKeyValueStoreChangeReasonKey set to NSUbiquitousKeyValueStoreAccountChange because tvOS exchanges your entire ubiquity key-value-store.

Maybe you could use that with some trickery to detect account changes, e.g. store a NSUUID in the ubiquity key-value-store, and when the value changes, it means there is a new account. But you cannot detect if an account is logged off.

Community
  • 1
  • 1
bio
  • 669
  • 4
  • 14