Posts under App & System Services topic

Post

Replies

Boosts

Views

Activity

New features for APNs token authentication now available
Team-scoped keys introduce the ability to restrict your token authentication keys to either development or production environments. Topic-specific keys in addition to environment isolation allow you to associate each key with a specific Bundle ID streamlining key management. For detailed instructions on accessing these features, read our updated documentation on establishing a token-based connection to APNs.
0
0
1.9k
Feb ’25
Apple Pay SDK JS version policy
What is the version policy for the Apple Pay SDK Javascript ? The documentation refers to this link : https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js The future updates will overrride the file on that link ? Is there a way to be notified of any changes ? We are using a previous version named v1 : https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js What are the risks not using changing to the lastesdt link ? Thank you for your help.
0
0
256
Mar ’25
SwiftData duplicates values inside array on insert()
After copying and inserting instances I am getting strange duplicate values in arrays before saving. My models: @Model class Car: Identifiable { @Attribute(.unique) var name: String var carData: CarData func copy() -> Car { Car( name: "temporaryNewName", carData: carData ) } } @Model class CarData: Identifiable { var id: UUID = UUID() var featuresA: [Feature] var featuresB: [Feature] func copy() -> CarData { CarData( id: UUID(), featuresA: featuresA, featuresB: featuresB ) } } @Model class Feature: Identifiable { @Attribute(.unique) var id: Int @Attribute(.unique) var name: String @Relationship( deleteRule:.cascade, inverse: \CarData.featuresA ) private(set) var carDatasA: [CarData]? @Relationship( deleteRule:.cascade, inverse: \CarData.featuresB ) private(set) var carDatasB: [CarData]? } The Car instances are created and saved to SwiftData, after that in code: var fetchDescriptor = FetchDescriptor<Car>( predicate: #Predicate<Car> { car in car.name == name } ) let cars = try! modelContext.fetch( fetchDescriptor ) let car = cars.first! print("car featuresA:", car.featuresA.map{$0.name}) //prints ["green"] - expected let newCar = car.copy() newCar.name = "Another car" newcar.carData = car.carData.copy() print("newCar featuresA:", newCar.featuresA.map{$0.name}) //prints ["green"] - expected modelContext.insert(newCar) print("newCar featuresA:", newCar.featuresA.map{$0.name}) //prints ["green", "green"] - UNEXPECTED! /*some code planned here modifying newCar.featuresA, but they are wrong here causing issues, for example finding first expected green value and removing it will still keep the unexpected duplicate (unless iterating over all arrays to delete all unexpected duplicates - not optimal and sloooooow).*/ try! modelContext.save() print("newCar featuresA:", newCar.featuresA.map{$0.name}) //prints ["green"] - self-auto-healed??? Tested on iOS 18.2 simulator and iOS 18.3.1 device. Minimum deployment target: iOS 17.4 The business logic is that new instances need to be created by copying and modifying previously created ones, but I would like to avoid saving before all instances are created, because saving after creating each instance separately takes too much time overall. (In real life scenario there are more than 10K objects with much more properties, updating just ~10 instances with saving takes around 1 minute on iPhone 16 Pro.) Is this a bug, or how can I modify the code (without workarounds like deleting duplicate values) to not get duplicate values between insert() and save()?
8
0
441
Mar ’25
UNNotificationRequest set timestamp to a relative time
The system calendar when showing a calendar event shows a relative timestamp on the notification versus all other apps which have a timestamp of when the notification was sent. Is there a way to set the timestamp to be relative? I am currently working on a calendar app and we should be able to use the same system that apple uses for its own calendar. Post about this on stack overflow from someone else a few years ago
1
0
322
Mar ’25
App Clip Closes Before SKOverlay Can Show “Open” Button When Live Activity Is Involved
I have an App Clip that uses SKOverlay.AppClipConfiguration to install the full app. Before I added a Live Activity call (Activity.request), the user could see “Install,” then “Open.” Now, once “Get” is tapped, the Clip immediately closes—no “Open” button appears. If I remove the Live Activity code, it works again. I’ve confirmed that parent/child entitlements match, and tested via TestFlight. Is there a known issue or recommended workaround for combining SKOverlay + Live Activities in an App Clip so it doesn’t dismiss prematurely? Any insights are appreciated! Note live activity is for App Clip only.
1
0
326
Mar ’25
Schema Migrations with CloudKit Not Working
I have not had any successful Schema Migration with CloudKit so far so I'm trying to do with with just very basic attributes, with multiple Versioned Schemas This is the code in my App Main var sharedModelContainer: ModelContainer = { let schema = Schema(versionedSchema: AppSchemaV4.self) do { return try ModelContainer( for: schema, migrationPlan: AppMigrationPlan.self, configurations: ModelConfiguration(cloudKitDatabase: .automatic)) } catch { fatalError("Could not create ModelContainer: \(error)") } }() var body: some Scene { WindowGroup { ItemListView() } .modelContainer(sharedModelContainer) } And this is the code for my MigrationPlan and VersionedSchemas. typealias Item = AppSchemaV4.Item3 enum AppMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] { [AppSchemaV1.self, AppSchemaV2.self, AppSchemaV3.self, AppSchemaV4.self] } static var stages: [MigrationStage] { [migrateV1toV2, migrateV2toV3, migrateV3toV4] } static let migrateV1toV2 = MigrationStage.lightweight( fromVersion: AppSchemaV1.self, toVersion: AppSchemaV2.self ) static let migrateV2toV3 = MigrationStage.lightweight( fromVersion: AppSchemaV2.self, toVersion: AppSchemaV3.self ) static let migrateV3toV4 = MigrationStage.custom( fromVersion: AppSchemaV3.self, toVersion: AppSchemaV4.self, willMigrate: nil, didMigrate: { context in // Fetch all Item1 instances let item1Descriptor = FetchDescriptor<AppSchemaV3.Item1>() let items1 = try context.fetch(item1Descriptor) // Fetch all Item2 instances let item2Descriptor = FetchDescriptor<AppSchemaV3.Item2>() let items2 = try context.fetch(item2Descriptor) // Convert Item1 to Item3 for item in items1 { let newItem = AppSchemaV4.Item3(name: item.name, text: "Migrated from Item1 on \(item.date)") context.insert(newItem) } // Convert Item2 to Item3 for item in items2 { let newItem = AppSchemaV4.Item3(name: item.name, text: "Migrated from Item2 with value \(item.value)") context.insert(newItem) } try? context.save() } ) } enum AppSchemaV1: VersionedSchema { static var versionIdentifier: Schema.Version = Schema.Version(1, 0, 0) static var models: [any PersistentModel.Type] { [Item1.self] } @Model class Item1 { var name: String = "" init(name: String) { self.name = name } } } enum AppSchemaV2: VersionedSchema { static var versionIdentifier: Schema.Version = Schema.Version(2, 0, 0) static var models: [any PersistentModel.Type] { [Item1.self] } @Model class Item1 { var name: String = "" var date: Date = Date() init(name: String) { self.name = name self.date = Date() } } } enum AppSchemaV3: VersionedSchema { static var versionIdentifier: Schema.Version = Schema.Version(3, 0, 0) static var models: [any PersistentModel.Type] { [Item1.self, Item2.self] } @Model class Item1 { var name: String = "" var date: Date = Date() init(name: String) { self.name = name self.date = Date() } } @Model class Item2 { var name: String = "" var value: Int = 0 init(name: String, value: Int) { self.name = name self.value = value } } } enum AppSchemaV4: VersionedSchema { static var versionIdentifier: Schema.Version = Schema.Version(4, 0, 0) static var models: [any PersistentModel.Type] { [Item1.self, Item2.self, Item3.self] } @Model class Item1 { var name: String = "" var date: Date = Date() init(name: String) { self.name = name self.date = Date() } } @Model class Item2 { var name: String = "" var value: Int = 0 init(name: String, value: Int) { self.name = name self.value = value } } @Model class Item3 { var name: String = "" var text: String = "" init(name: String, text: String) { self.name = name self.text = text } } } My experiment was: To create Items for every version of the schema Updating the typealias along the way to reflect the latest Item version. Updating the Schema in my ModelContainer to reflect the latest Schema Version. By AppSchemaV4, I have expected all my Items to be displayed/migrated to Item3, but it does not seem to be the case. I can only see newly created Item3 records. My question is, is there something wrong with how I'm doing the migrations? or are migrations not really working with CloudKit right now?
1
0
449
Mar ’25
Migrating a Paid App to In-App Subscriptions
Hello, I’m trying to change the business model of my app to in-app subscriptions. My goal is to ensure that previous users who paid for the app have access to all premium content seamlessly, without even noticing any changes. I’ve tried using RevenueCat for this, but I’m not entirely sure it’s working as expected. I would like to use RevenueCat to manage subscriptions, so I’m attempting a hybrid model. On the first launch of the updated app, the plan is to validate the app receipts, extract the originalAppVersion, and store it in a variable. If the original version is lower than the latest paid version, the isPremium variable is set to true, and this status propagates throughout the app. For users with versions equal to or higher than the latest paid version, RevenueCat will handle the subscription status—checking if a subscription is active and determining whether to display the paywall for premium features. In a sandbox environment, it seems to work fine, but I’ve often encountered situations where the receipt doesn’t exist. I haven’t found a way to test this behavior properly in production. For example, I uploaded the app to TestFlight, but it doesn’t validate the actual transaction for a previously purchased version of the app. Correct me if I’m wrong, but it seems TestFlight doesn’t confirm whether I installed or purchased a paid version of the app. I need to be 100% sure that users who previously paid for the app won’t face any issues with this migration. Is there any method to verify this behavior in a production-like scenario that I might not be aware of? I’m sharing the code here to see if you can confirm that it will work as intended or suggest any necessary adjustments. func fetchAppReceipt(completion: @escaping (Bool) -> Void) { // Check if the receipt URL exists guard let receiptURL = Bundle.main.appStoreReceiptURL else { print("Receipt URL not found.") requestReceiptRefresh(completion: completion) return } // Check if the receipt file exists at the given path if !FileManager.default.fileExists(atPath: receiptURL.path) { print("The receipt does not exist at the specified location. Attempting to fetch a new receipt...") requestReceiptRefresh(completion: completion) return } do { // Read the receipt data from the file let receiptData = try Data(contentsOf: receiptURL) let receiptString = receiptData.base64EncodedString() print("Receipt found and encoded in base64: \(receiptString.prefix(50))...") completion(true) } catch { // Handle errors while reading the receipt print("Error reading the receipt: \(error.localizedDescription). Attempting to fetch a new receipt...") requestReceiptRefresh(completion: completion) } } func validateAppReceipt(completion: @escaping (Bool) -> Void) { print("Starting receipt validation...") guard let receiptURL = Bundle.main.appStoreReceiptURL else { print("Receipt not found on the device.") requestReceiptRefresh(completion: completion) completion(false) return } print("Receipt found at URL: \(receiptURL.absoluteString)") do { let receiptData = try Data(contentsOf: receiptURL, options: .alwaysMapped) print(receiptData) let receiptString = receiptData.base64EncodedString(options: []) print("Receipt encoded in base64: \(receiptString.prefix(50))...") let request = [ "receipt-data": receiptString, "password": "c8bc9070bf174a8a8df108ef6b8d2ae3" // Shared Secret ] print("Request prepared for Apple's validation server.") guard let url = URL(string: "https://buy.itunes.apple.com/verifyReceipt") else { print("Error: Invalid URL for Apple's validation server.") completion(false) return } print("Validation URL: \(url.absoluteString)") var urlRequest = URLRequest(url: url) urlRequest.httpMethod = "POST" urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: request) URLSession.shared.dataTask(with: urlRequest) { data, response, error in if let error = error { print("Error sending the request: \(error.localizedDescription)") completion(false) return } guard let data = data else { print("No response received from Apple's server.") completion(false) return } print("Response received from Apple's server.") do { if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] { print("Response JSON: \(json)") // Verify original_application_version if let receipt = json["receipt"] as? [String: Any], let appVersion = receipt["original_application_version"] as? String { print("Original application version found: \(appVersion)") // Save the version in @AppStorage savedOriginalVersion = appVersion print("Original version saved in AppStorage: \(appVersion)") if let appVersionNumber = Double(appVersion), appVersionNumber < 1.62 { print("Original version is less than 1.62. User considered premium.") isFirstLaunch = true completion(true) } else { print("Original version is not less than 1.62. User is not premium.") completion(false) } } else { print("Could not find the original application version in the receipt.") completion(false) } } else { print("Error parsing the response JSON.") completion(false) } } catch { print("Error processing the JSON response: \(error.localizedDescription)") completion(false) } }.resume() } catch { print("Error reading the receipt: \(error.localizedDescription)") requestReceiptRefresh(completion: completion) completion(false) } } Some of these functions might seem redundant, but they are intended to double-check and ensure that the user is not a previous user. Is there any way to be certain that this will work when the app is downloaded from the App Store? Thanks in advance!
1
0
464
Mar ’25
WeatherKit - hourly temperature details
we’re looking to get some clarification around how the hourly forecasts should be interpreted to ensure we’re using your data in the correct manner. If you could provide the answers to the following questions would be extremely helpful: 1. What do the data points (e.g temperature) in the hourly forecast represent for a future hour? Do they represent the expected average over that future hour or do they represent the forecast for the point in time at the top of the hour? 2. What do those same data points represent in the hourly forecast for an hour which has already begun? e.g. it’s 8:30 and we pull the hourly forecast and the 8:00 hour is still returned. Which of the following would be the correct interpretation for the values returned for the 8:00 hour: The values represent the forecast for the point in time at the top of the 8:00 hour (if this is the case we would expect it to stop updating) The values represent the current forecast i.e. what the weather is right now The values represent the average over the remaining portion of the 8:00 hour The values represent the average over the full 8:00 hour including both the portion which has already elapsed and the portion which is still to come 3. What does the data represent after the hour (i.e. looking at historical hours)? Is it: The last forecast made within the hour? If so, is that point-in-time or average for the hour (as explained above)? The actual weather for that hour (using some non-forecast measure of real weather)? If so, again is that point-in-time at top of hour / point-in-time at end of hour / average over the hour?
2
0
267
Mar ’25
UDP Broadcast/Multicast Reception Stops for Intervals
Our app receives real-time GPS and aircraft data from devices via UDP broadcast and/or multicast on a WiFi network created by the device. We have identified that the iPhone or iPad will just stop receiving UDP broadcast/multicast data for an interval of time. In general, it appears after roughly every 128KB of data is received. In the attached screenshot from Xcode instruments, you can see the data reception alternating on/off. We have verified with Wireshark that the data is still flowing during that entire time period. And by tracking bytes received the app ultimately receives about 55% of the bytes, which tracks with the Network graph. We have used different approaches to the network code, including GCDAsyncUdpSocket, BSD Sockets, and the Network framework. We've tried it on background threads and the main thread. Tested it on iPads and iPhones. All produce the same result. The data is just never reaching the app code. Any insight on what may be temporarily disabling data reception?
1
0
270
Mar ’25
macOS + ARM + USB/C to get VCP code from external monitor via IOAVServiceReadI2C
Good morning, I'm encountering reliability issues with DDC/CI communication when using USB-C connection. Initially using ddc-hi (which uses this package), I ran into several issues that I've partially resolved but still need help addressing. Environment OS: macOS Display Connection: USB-C for _ in 1 ... (numOfRetryAttemps ?? 4) + 1 { for _ in 1 ... max((numOfWriteCycles ?? 2) + 0, 1) { usleep(writeSleepTime ?? 10000) success = IOAVServiceWriteI2C(service, UInt32(ARM64_DDC_7BIT_ADDRESS), UInt32(dataAddress), &packet, UInt32(packet.count)) == 0 } if !reply.isEmpty { usleep(readSleepTime ?? 50000) if IOAVServiceReadI2C(service, UInt32(ARM64_DDC_7BIT_ADDRESS), 0, &reply, UInt32(reply.count)) == 0 { success = self.checksum(chk: 0x50, data: &reply, start: 0, end: reply.count - 2) == reply[reply.count - 1] } } if success { return success } usleep(retrySleepTime ?? 20000) } The result from IOAVServiceReadI2C is not reliable in some cases. Do we have any other API to get VCP code from monitor like Intel version done. The previous APIs weren’t working anymore on the M1 GPU, the IOFramebuffer was now an IOMobileFramebuffer and the IOI2C* functions weren’t doing anything.
0
0
339
Mar ’25
How to update multiTokenContexts if ApplePayPaymentRequest does not initialize multiTokenContexts
https://developer.apple.com/documentation/apple_pay_on_the_web/applepaypaymentrequest/3955945-multitokencontexts According to this document, I know that I can initialize a multiTokenContexts when initializing ApplePayPaymentRequest. But I am now facing a tricky problem. If the user's order does not require multiTokenContexts, then I will not initialize this field when I first make ApplePayPaymentRequest. When the user is in the payment process, I may update multiTokenContexts. But this time, the update is not allowed, ApplePay will be cancelled and the payment will be closed. For example, if the user's address in Apple Pay is different, I need to update multiTokenContexts to support the payment of goods to multiple merchants, which will generate an update of multiTokenContexts. MultiTokenContexts can be updated in the onshippingcontactselected method. https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession/1778009-onshippingcontactselected My question is that from the beginning, there was no multiTokenContexts to update multiTokenContexts in onshippingcontactselected, which would cause the user to close the payment and need to manually click to pay again. This user experience is not very friendly. Is there a better way for me to go from no multiTokenContexts to multiTokenContexts without interrupting the user's payment process?
0
0
148
Mar ’25
Is it work startMonitoring from DeviceActivityMonitorExtension's eventDidReachThreshold function?
I want to monitor again from the bellow function of DeviceActivityMonitorExtension. I have the function of startMonitoring like this. override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) { super.eventDidReachThreshold(event, activity: activity) startMonitoring() } public func startMonitoring() { let startTime = DateComponents(hour: 0, minute: 0, second: 0) let endTime = DateComponents(hour: 23, minute: 59, second: 59)//DateComponents(hour: 11, minute: 0, second: 0)// let schedule = DeviceActivitySchedule( intervalStart: startTime,//DateComponents(hour: 0, minute: 0, second: 0), intervalEnd: endTime, repeats: true //warningTime: DateComponents(minute:1) ) let selection: FamilyActivitySelection = savedSelection() ?? FamilyActivitySelection() let center = DeviceActivityCenter() let selections = self.savedSelection() ?? FamilyActivitySelection() let applications = selections.applicationTokens let categories = selections.categoryTokens let webCategories = selections.webDomainTokens let store = ManagedSettingsStore() store.shield.applicationCategories = ShieldSettings.ActivityCategoryPolicy.specific(categories, except: Set()) store.shield.applications = applications store.shield.webDomains = webCategories let scheduleHard = DeviceActivitySchedule( intervalStart: startTime,//DateComponents(hour: 0, minute: 0, second: 0), intervalEnd: endTime, repeats: true //warningTime: DateComponents(minute:1) ) let event = DeviceActivityEvent( applications: selection.applicationTokens, categories: selection.categoryTokens, webDomains: selection.webDomainTokens, threshold: DateComponents(minute: 0)//timeLimitToUseApp i.e for 15 mins ) do { try center.startMonitoring( .weekend, during: scheduleHard, events: [ .weekend: event, ] ) print("ScreenTime Monitoring Started") } catch let error { print(error.localizedDescription) } } Please provide us with a solution about starting monitoring from DeviceActivityMonitoringExtension's eventDidReachThreshold function or if there is any other way.
0
0
379
Mar ’25
SetFocusFilterIntent `perform()` method is not called on iOS 18 beta
I’ve set up a focus filter, but the perform() method in SetFocusFilterIntent isn't called when the focus mode is toggled on or off on my iPhone since I updated to iOS 18 beta (22A5326f). I can reproduce the issue for my app, but focus filters are also broken for any third-party apps installed on my phone, so I guess it's not specific to how I've implemented my filter intent. This used to work perfectly on iOS 17. I didn't change a single line of code, and it broke completely on the latest iOS 18 beta. I've filed a bug report including a sysdiagnose (FB14715113). To the developers out there, is this something you are also observing in your apps?
3
0
781
Mar ’25
FamilyActivityPicker: manage own device AND children device
Hello, I am unable to figure out how I tell the FamilyActivityPicker whether it should show apps installed on my personal device (to be used with AuthorizationCenter.shared.requestAuthorization(for: .individual)) or apps installed on my child’s device (authenticated their phone via AuthorizationCenter.shared.requestAuthorization(for: .child)). Is there any parameter or SwiftUI modifier I need to apply? Otherwise, how does the user or the app know which token belongs to them and which token belongs to their child’s device? Radar: FB17020977 Thanks a lot for your help!
0
0
122
Mar ’25
How to test application using Thread networking on MacOS?
I would like to test running some Thread Networking code on my MacOS machine: import ThreadNetwork let client = THClient() let bIsPreferredAvailable = await client.isPreferredAvailable() but I get some errors when trying to create an instance of the THClient class: Client: -[THClient connectToXPCService]_block_invoke - CTCS XPC Client is interrupted. Client: -[THClient getConnectionEntitlementValidity]_block_invoke - clientProxyWithErrorHandler Error: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.ThreadNetwork.xpc" UserInfo={NSDebugDescription=connection to service named com.apple.ThreadNetwork.xpc} Client: -[THClient init] - XPC Client Init Failed Invalidating XPC connection. Client: -[THClient getConnectionEntitlementValidity]_block_invoke - clientProxyWithErrorHandler Error: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.ThreadNetwork.xpc" UserInfo={NSDebugDescription=connection to service named com.apple.ThreadNetwork.xpc} How can I get the code to run?
0
0
264
Mar ’25
Auto Renew Subscription Model
Hi, I want to offer an auto-renewable subscription (e.g., $1/month) that grants users (10 document analyses per month), with the count resetting at the start of each billing cycle. -Unused analyses will not roll over to the next month- Additionally, any analyses generated while the subscription is active will remain accessible to the user permanently, even if they cancel the subscription. The paywall, app description, and metadata will clearly state that the subscription grants (10 document analyses per month with no rollover) We want this to be implemented as an auto-renewable subscription model, not as a consumable service or a token/credit system (which we want to avoid). Is this model acceptable under Apple’s guidelines, or would it be considered a token/credit system? Any insights or alternative suggestions would be appreciated.. Thanks
0
0
320
Mar ’25
HKAnchoredObjectQuery updateHandler stops working with error
Hi! I am using the HKAnchoredObjectQuery to first get a snapshot of the initial results, and then trigger an updateHandler. I need to handle the initial results and the updates separately, which is why I implemented two completions. When I test the code, it works for a while. New and deleted samples trigger the updateHandler. However, after a while there appears an error: [connection] nw_read_request_report [C2] Receive failed with error "Software caused connection abort" Followingly, the updateHandler will stop getting triggered when I add updates in Apple health. Anyone have experience with this? func getMostRecentSample(for sampleType: HKSampleType, anchorKey: String, completion: @escaping (HKQuantitySample?, Error?) -> Swift.Void, updateHandler: @escaping (HKQuantitySample, Error?) -> Swift.Void) {     // If it is the first initialization, anchor is passed as nil     var anchor: HKQueryAnchor? = nil // Check for previous saved anchor in userdefaults     if UserDefaults.standard.object(forKey: anchorKey) != nil {       let data = UserDefaults.standard.object(forKey: anchorKey) as! Data       do {         guard let newAnchor = try NSKeyedUnarchiver.unarchivedObject(ofClass: HKQueryAnchor.self, from: data) else {           print("Could not parse anchor to HKQueryAnchor type")           return         }         anchor = newAnchor       } catch {         print("Error retreiving anchor from UserDefaults")       }     }     let query = HKAnchoredObjectQuery(type: sampleType,                      predicate: nil,                      anchor: anchor,                      limit: HKObjectQueryNoLimit                       ) { (query, samplesOrNil, _, newAnchor, errorOrNil) in       guard let samples = samplesOrNil as? [HKQuantitySample] else {         fatalError("*** An error occurred during the initial query: \(errorOrNil!.localizedDescription) ***")       }       if let anchor = newAnchor {         do {           let data = try NSKeyedArchiver.archivedData(withRootObject: anchor as Any, requiringSecureCoding: false)           UserDefaults.standard.set(data, forKey: anchorKey)         } catch {           print("Error retreiving anchor from UserDefaults")         }       }       completion(samples.last, nil)     }           // Setting up long-running query     query.updateHandler = { (query, samplesOrNil, _, newAnchor, errorOrNil) in       guard let samples = samplesOrNil as? [HKQuantitySample] else {         fatalError("*** An error occurred during an update: \(errorOrNil!.localizedDescription) ***")       }       if let anchor = newAnchor {         do {           let data = try NSKeyedArchiver.archivedData(withRootObject: anchor as Any, requiringSecureCoding: false)           UserDefaults.standard.set(data, forKey: anchorKey)         } catch {           print("Error retreiving anchor from UserDefaults")         }       }       if let sample = samples.last {         updateHandler(sample, nil)       }     }     self.healthStore.execute(query)   }
2
0
1.2k
Mar ’25