Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS15: NSPersistentCloudKitContainer: how to un-share objects?

I’m working on an app that uses the new sharing support in iOS 15 using NSPersistentCloudKitContainer. I do not see a way to tell Core Data that an object, or set of objects, is no longer shared.

For example, if I create a set of objects and then call share(_:to:completion:), the objects are shared properly and moved to a new, custom CKRecordZone, as expected.

Now, if the user stops sharing an object using UICloudSharingController, the CKShare that Core Data created is properly deleted from CloudKit, but the objects are still in the custom zone, and Core Data still has the original CKShare associated with those objects. So, when I call fetchShares(matching:), I still get the CKShare, but of course, that is no longer valid. In the past, with my own code, I’d use UISharingControllers delegate to get notified that the user stopped sharing, and then update my model. But there doesn’t seem to be a way to tell Core Data about the change.

Forcing Core Data to fetch CloudKit changes by either moving the app to background and then foreground, or by stopping the app and relaunching does not cause Core Data to notice the change to the share.

Does anyone know how to tell Core Data that these objects are no longer shared?

like image 504
coping Avatar asked Jul 31 '21 16:07

coping


People also ask

What is ‘shared with You’ in iOS 15?

Apple rolled out iOS 15 for everyone last week, bringing new features to make your daily routine easy. Among the new features that are available to you is ‘Shared With You’ – a new section that highlights content shared by others over the Messages app.

How to stop Safari from syncing with iCloud?

If you don’t want your iPhone’s Safari settings to sync over to other Apple devices, open Safari, scroll down to the bottom of the Start Page, and tap on Edit . Inside the Customize Start Page, turn off the Use Start Page on All Devices toggle to disable syncing through iCloud.

How to disable ‘shared with You’ feature on iPhone?

You can even choose to disable ‘Share With You’ completely, not just for Safari. For this, open the Settings app first. Then tap on Messages. Scroll down and tap on Shared with You. Now, turn off the Safari toggle. If you want to disable the ‘Shared With You’ feature completely, for all apps, then toggle off the Automatic Sharing option at the top.

Why does the shared with you section keep appearing in Safari?

If you have disabled Shared with You for Safari, a contact, or throughout iOS, but the section continues to show up or reappears after some time inside the app, then it may be happening because you have multiple Apple devices signed in to the same iCloud account.


2 Answers

I worked around this by always checking to see if the share actually exists in CloudKit, rather than relying on the existence of a CKShare from fetchShares(matching:). I get the URL from the CKShare returned from fetchShares(matching:) and call this:

private func remoteShare(at url: URL) async throws -> CKShare? {
        do {
            let metadata = try await cloudKitContainer.shareMetadata(for: url)
            return metadata.share
        } catch let error as CKError {
            if error.retryable {
                throw RemoteError.retryable
            } else if error.userInterventionRequiredError {
                throw RemoteError.userInterventionRequired
            } else if error.code == .unknownItem {
                return nil
            } else {
                throw RemoteError.remoteFailure
            }
        } catch {
            throw RemoteError.remoteFailure
        }
    }
}

If I get unknownItem that means there is no share on the remote, so the object is not actually shared.

The RemoteError is my custom error handling, and I have some extensions on CKError to categorize the errors.

like image 162
coping Avatar answered Oct 17 '22 09:10

coping


Another workaround to the issue is to create a copy of the object being shared, and then deleting the original. It's not elegant, but it works in the meantime. (Hopefully Apple will address this at some point with a better solution.) The copy will be placed in the default zone like it was before you shared the original. You'll be left with an empty share zone, but I dealt with that by running a background task upon app launch that deletes all empty share zones, so it doesn't get out of hand.

I haven't tried the solution posted by Dharman, but I imagine it's slower than querying the local cache. Using the method above, you can still use the "isShared" code from the demo app.

like image 38
M. Chollar Avatar answered Oct 17 '22 08:10

M. Chollar