Post

Replies

Boosts

Views

Activity

`NSPersistentStore` metadata update synchronisation
I'm attempting to synchronise an offline data store in core data with an online store. To maintain the last synchronisation point for both data coming in to the local cache, and data going out, I'm using change tokens. An NSPersistentHistoryToken to track the last data that went out, and a server provided token for the data coming in. In terms of the best place to store the tokens, it seems to me it would be in the local store (NSPersistentStore) itself – saving the incoming data and the token can then be tied into a neat save transaction; if there's problem saving the incoming data, the token won't be updated. One way of achieving this would be to create a new Entity in my model to track the tokens, but it appears NSPersistentStoreCoordinator already has a tidy pair of meta data functions that might be perfect for this: metadata(for:) and setMetadata(_:for:). However, as I am considering updating the metadata after operations on separate managed object contexts (one for incoming remote data, one for outgoing remote data) I'm concerned about synchronisation. That's because the metadata functions operate at the persistent store coordinator level rather than the context level. Potentially, if two perform(_:) blocks are running concurrently the metadata could become stale between the calls to metadata(for:) and setMetadata(_:for:), what's more, as store meta data is apparently only persisted upon a context save we'd want to restrict another context getting access to this new metadata until it's been permanently persisted as otherwise it may write changes for another context that were ultimately rolled-back. What's the reccommended approach to handle this? Is it as simple as wrapping the meta data fetch, update and context save calls in to an operation that gets called on a serialised queue? Something like: let metadataSerialQueue = DispatchQueue("metadata-serial-queue")  context1.perform {     // context update operations     ...     metadataSerialQueue.sync {         var metadata = psc.metadata(for: store)         // update change token         metadata["change-token"] = changeToken         psc.setMetadata(metadata, for: store)         do {             try context1.save()         }         catch let e as NSError {             print("Failed to save context in store change. Rolling back. \(e)")             context1.rollback()         }     } } Or is that pushing store metadata outside of its use case?
4
1
1.1k
Nov ’20
Silent Push Notifications in dev environment?
I'm trying to debug why I'm not receiving silent push notifications in the dev environment. In terms of setup: I create a CKSubscription.NotificationInfo with shouldSendContentAvailable set to true. Add that to a CKDatabaseSubscription and send to CloudKit via my private CKDatabase's save(_: completionHandler:) which returns successfully. I confirm the subscription exists in subsequent launches via CKFetchSubscriptionsOperation. In my AppDelegate I call application.registerForRemoteNotifications() in application(_:didFinishLaunchingWithOptions:) A device token is received in application(_:didRegisterForRemoteNotificationsWithDeviceToken:) The app is setup with entitlements for Push, CloudKit, and Background Modes with Remote Notifications and Background Processing checked. I run the app on two hardware devices (iPhone and Mac mini) and initiate a record update on either device. However, I don't receive a notification that an update has taken place on either device; application(_:didReceiveRemoteNotification:fetchCompletionHandler) is never called. I don't see any pushes fired via the Dashboard, and I can't seem to find record of the subscription – even though I can see them when I query via a CKFetchSubscriptionsOperation on the device. Am I missing something? Is there a good way of debugging this?
1
0
799
Nov ’20
Full Screen Cover and iPhone Orientation
Currently, there seems to be an all or nothing approach to supporting rotation on iPhone. Either every screen in your UI supports rotation, or none of them do. For a some apps however, that approach won't work. They have a number of screens that don't adapt well to a super letterboxed screen size, and a number of others that would benefit from the additional screen space. Previous discussion on this issue recommends the use of size classes, but this advice fails to recognise that some use cases simply aren't suited to being super letterboxed. Apple's own UI design is tacit acknowledgement of this: For example, the main UI of the Camera app stays fixed in the portrait orientation in the shooting mode, but presents a rotatable modal to review photos and videos. Even Springboard, the home screen of the iPhone, remains locked in the portrait orientation whilst allowing an app to be presented in landscape. Social media and news apps are another example: generally anchored around a portrait newsfeed that doesn't adapt well to extreme letterboxing, but surfacing rich media such as images, videos, charts and other interactive elements that could use the flexibility of landscape presentation. (News app, looking at you.) Is it time to re-visit the rotation characteristics of the phone vs. tablet idioms? Is this all-or-nothing approach to rotation serving the platform well? Regardless, app designers at Apple and elsewhere are creating apps that use this hybrid approach to rotation. And as things stand today, SwiftUI makes it very difficult. A rough equivalent can be made using a ZStack and observing the device orientation, but this requires hiding the status bar and provides no way to honor a user's portrait lock settings. The only other option, as far as I can tell, is building the app using UIKit view controllers, to thread through supportedInterfaceOrientations hooks. Personally, what I'd love to see is a new presentationInterfaceOrientations(_:) hook on View, that allows a fullScreenCover presentation to be specified as supporting an alternative orientation set. This could be iPhone only, and should serve the majority of use cases. However, in the meantime, it would be great to know if there's a technique that can get the UIKit behavior in a SwiftUI app that doesn't require rewriting the entire container view hierachy in UIKit.
0
1
853
Oct ’23