I'm using NSPersistentCloudKitContainer with Core Data and I receive errors because my iCloud space is full. The errors printed are the following: <CKError 0x280df8e40: "Quota Exceeded" (25/2035); server message = "Quota exceeded"; op = 61846C533467A5DF; uuid = 6A144513-033F-42C2-9E27-693548EF2150; Retry after 342.0 seconds>.
I want to inform the user about this issue, but I can't find a way to access the details of the error. I'm listening to NSPersistentCloudKitContainer.eventChangedNotification, I receive a error of type .partialFailure. But when I want to access the underlying errors, the partialErrorsByItemID property on the error is nil.
How can I access this Quota Exceeded error?
import Foundation
import CloudKit
import Combine
import CoreData
class SyncMonitor {
fileprivate var subscriptions = Set<AnyCancellable>()
init() {
NotificationCenter.default.publisher(for: NSPersistentCloudKitContainer.eventChangedNotification)
.sink { notification in
if let cloudEvent = notification.userInfo?[NSPersistentCloudKitContainer.eventNotificationUserInfoKey] as? NSPersistentCloudKitContainer.Event {
guard let ckerror = cloudEvent.error as? CKError else {
return
}
print("Error: \(ckerror.localizedDescription)")
if ckerror.code == .partialFailure {
guard let errors = ckerror.partialErrorsByItemID else {
return
}
for (_, error) in errors {
if let currentError = error as? CKError {
print(currentError.localizedDescription)
}
}
}
}
} // end of sink
.store(in: &subscriptions)
}
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hello,
The app displays a list of posts (Post), and for each post, a list of tags (Tag). The Post detail view shows a list of tags for a given post. The Tag detail view shows the post name and the tag name. Both Post and Tag are ObservableObject, and both are passed to the environment when a NavigationLink is tapped.
On the master List with all the posts, you tap on a post. The post is passed in the environment. It's working because the detail view for the selected post is correctly displayed, and you can choose to display a tag from the tags in the displayed post.
But when you tap on a tag to view the details, the app crashes: the post object is not in the environment. No ObservableObject of type Post found. A View.environmentObject(_:) for Post may be missing as an ancestor of this view.
Why? The post object in the PostView, so it should be also available in the TagView because the TagView can only be displayed from the PostView.
Thanks
Axel
import SwiftUI
class Store: ObservableObject {
@Published var posts: [Post] = [
Post(name: "Post 1", tags: [.init(name: "Tag 1"), .init(name: "Tag 2")]),
Post(name: "Post 2", tags: [.init(name: "Tag 1"), .init(name: "Tag 2")])
]
}
class Post: ObservableObject, Identifiable, Hashable {
@Published var name: String = ""
@Published var tags: [Tag] = []
var id: String { name }
init(name: String, tags: [Tag]) {
self.name = name
self.tags = tags
}
static func == (lhs: Post, rhs: Post) -> Bool {
return lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
class Tag: ObservableObject, Identifiable, Hashable {
@Published var name: String = ""
var id: String { name }
init(name: String) {
self.name = name
}
static func == (lhs: Tag, rhs: Tag) -> Bool {
return lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
struct PassEnvironmentObject: View {
@StateObject private var store: Store = .init()
var body: some View {
NavigationStack {
List {
ForEach(store.posts) { post in
NavigationLink(post.name, value: post)
}
}
.navigationDestination(for: Post.self) { post in
PostView()
.environmentObject(post)
}
.navigationDestination(for: Tag.self) { tag in
TagView()
.environmentObject(tag)
}
}
}
}
struct PostView: View {
@EnvironmentObject private var post: Post
var body: some View {
List {
ForEach(post.tags) { tag in
NavigationLink(tag.name, value: tag)
}
}
}
}
struct TagView: View {
@EnvironmentObject private var post: Post
@EnvironmentObject private var tag: Tag
var body: some View {
VStack {
Text(post.name)
Text(tag.name)
}
}
}
struct PassEnvironmentObject_Previews: PreviewProvider {
static var previews: some View {
PassEnvironmentObject()
}
}
Hello
I’ve a question regarding CLLocationManager as I’m observing a strange behaviour when receiving location updates. And I don’t really know what could be the culprit here.
Some information regarding the device:
Device: iPhone Xs Max
OS: iOS 16.1 beta 4
App Background Modes: locations updates checked.
CLLocationManager setup:
CLAuthorizationStatus: authorizedWhenInUse
CLAccuracyAuthorization: fullAccuracy
allowsBackgroundLocationUpdates is ON
pausesLocationUpdatesAutomatically is OFF (but toggle to turn in on in the POC)
activityType (CLActivityType): .otherNavigation (but tried other options).
desiredAccuracy (CLLocationAccuracy) : kCLLocationAccuracyNearestTenMeters (to receive GPS updates, and not cell towers)
distanceFilter CLLocationDistance): kCLDistanceFilterNone (-1) or 0.
When I record with the device unlocked, everything is working fine with the app either in foreground or in background. It receives location updates as I walk around with quite good accuracy (between 5 and 15 meters, see attachment).
But I notice that when the device is locked in my pocket, the location service stops receiving updates after a while (like few minutes). I tried with Wi-Fi off and it behaves the same. You can see that in my screenshots attached: many values are incorrect (speed, course). When I open the app again (not crashed), the locations are received again but the horizontalAccuracy is not very good: it’s as if it was not using the GPS anymore.
I tried with low power mode enabled and disabled, and I think it behaves the same but maybe not? Is the low power mode responsible for this discrepancies?
As far as I know, it does not modify location services accuracy (only network, background tasks, etc.).
Thanks
I'm building an iOS app (the supported destinations in the app target are iOS, iPad and Mac - Designed for iPad). I've many SPM frameworks in order to split my codebase in different features. I want to export the localisations for the different packages and the app using Xcode but it fails. I followed the Apple guide regarding SPM localization: the packages contains a Resources folder with a folder for each language supported. I specified the platforms .iOS(.v16) in the packages.
But it seems that exporting the localisations using the Product > Export Localizations feature in Xcode compiles also the packages and app for macOS. Here is the error message:
Showing Recent Messages
/Users/axel/Developer/AppName/Packages/Helpers/Sources/Helpers/UIKit/UIImage+Extension.swift:7:14:
No such module 'UIKit'
/Users/axel/Developer/AppName/Packages/Helpers/Sources/Helpers/UIKit/UIImage+Extension.swift:7:14:
UIKit is not available when building for macOS. Consider using `#if canImport(UIKit)` to conditionally import this framework.
Is there a way to have the export feature work when building an iOS app with packages specified for iOS?
When using Swift Packages in Xcode, is there a way to exclude files conditionally (in DEBUG or similar)? I know I can exclude files but I want them while in development.
I have a package that contains developments resource/assets (used to seed a Core Data database for the simulator + for Previews, with images and files), but I don't want to include these files in the package used by the real app when archiving.
Can we achieve that?
In UIKit, we can add an insets to a MKMapView with setVisibleMapRect to have additional space around a specified MKMapRect. It's useful for UIs like Apple Maps or FlightyApp (see first screenshot attached). This means we can have a modal sheet above the map but still can see all the content added to the map.
I'm trying to do the same for a SwiftUI Map (on iOS 17) but I can't find a way to do it: see screenshot 2 below. Is it possible to obtain the same result or should I file a feedback for an improvement?
I want to find the "last Sunday of a month before the current date" in Swift, but using the Calendar nextDate function doesn't work (always returns nil).
var calendar: Calendar = Calendar(identifier: .gregorian)
calendar.timeZone = .gmt
let lastSundayDateComponents: DateComponents = DateComponents(
weekday: 1,
weekdayOrdinal: -1
)
let previousLastSundayDate: Date? = calendar.nextDate(
after: Date.now,
matching: lastSundayDateComponents,
matchingPolicy: .nextTime,
repeatedTimePolicy: .first,
direction: .backward
)
print(previousLastSundayDate ?? "Not found") // "Not found"
If I use a positive weekdayOrdinal, it's working normally and the same nextDate method provides the correct date.
let firstSundayDateComponents: DateComponents = DateComponents(
weekday: 1,
weekdayOrdinal: 1
)
When I check if the date components can provide a valid date for the given calendar, it returns false...
let lastSundayInNovember2023DateComponents: DateComponents = DateComponents(
year: 2023,
month: 11,
weekday: 1,
weekdayOrdinal: -1
)
// THIS RETURNS FALSE
let isValid: Bool = lastSundayInNovember2023DateComponents.isValidDate(in: calendar)
print(isValid) // false
... even if the correct date can be created.
let lastSundayInNovember2023: Date = calendar.date(from: lastSundayInNovember2023DateComponents)!
print(lastSundayInNovember2023) // 2023-11-26 00:00:00 +0000
Is that a bug in Foundation?
Hello,
I'm currently migrating my app location service to use the new CLLocationUpdate.Updates.
I'm trying to understand what can fail in this AsyncSequence. Based on the previous CLError, I thought authorisation was one of them for example but it turns out that this is handled by the CLLocationUpdate where we can check different properties.
So, is there a list of errors available somewhere?
Thanks
Axel, @alpennec
Hello,
I want to update the prices in all territories of an auto-renewable subscription at once (in a single request). I know it's possible to do it territory by territory using the Create a Subscription Price Change API endpoint, but this means I need to call this API for every territory. And I have a lot of subscriptions I need to update.
There is an another API endpoint that seems to allow to Modify an Auto-Renewable Subscription.
For the countries where I want to change the price, I fetch the subscription price points using the List All Price Points for a Subscription API endpoint.
When I call this API endpoint with the following body (that is the expected body content for this endpoint):
{
"data": {
"type": "subscriptions",
"relationships": {
"prices": {
"data": [
{
"id": "eyJzIjoiNjc0MDAyMTQ5NiIsInQiOiJDQU4iLCJwIjoiMTAwMDEifQ",
"type": "subscriptionPrices"
},
{
"type": "subscriptionPrices",
"id": "eyJzIjoiNjc0MDAyMTQ5NiIsInQiOiJVU0EiLCJwIjoiMTAwMDEifQ"
}
]
}
},
"id": "6740021496"
},
"included": [
{
"relationships": {
"subscriptionPricePoint": {
"data": {
"id": "eyJzIjoiNjc0MDAyMTQ5NiIsInQiOiJDQU4iLCJwIjoiMTAwMDEifQ",
"type": "subscriptionPricePoints"
}
},
"territory": {
"data": {
"type": "territories",
"id": "CAN"
}
},
"subscription": {
"data": {
"id": "6740021496",
"type": "subscriptions"
}
}
},
"id": "eyJzIjoiNjc0MDAyMTQ5NiIsInQiOiJDQU4iLCJwIjoiMTAwMDEifQ",
"attributes": {
"preserveCurrentPrice": true
},
"type": "subscriptionPrices"
},
{
"attributes": {
"preserveCurrentPrice": true
},
"id": "eyJzIjoiNjc0MDAyMTQ5NiIsInQiOiJVU0EiLCJwIjoiMTAwMDEifQ",
"type": "subscriptionPrices",
"relationships": {
"subscription": {
"data": {
"type": "subscriptions",
"id": "6740021496"
}
},
"subscriptionPricePoint": {
"data": {
"type": "subscriptionPricePoints",
"id": "eyJzIjoiNjc0MDAyMTQ5NiIsInQiOiJVU0EiLCJwIjoiMTAwMDEifQ"
}
},
"territory": {
"data": {
"type": "territories",
"id": "USA"
}
}
}
}
]
}
I receive a 409 error:
{
"errors" : [ {
"id" : "5b6a4b62-686c-4a65-87ba-e16131db517b",
"status" : "409",
"code" : "ENTITY_ERROR",
"title" : "There is a problem with the request entity",
"detail" : "User is not allowed to edit.",
"source" : {
"pointer" : "subscriptionPrices"
}
} ]
}
I made sure
my bearer authorisation token is correct and still valid (not expired).
the p8 key has Admin rights
Can this PATCH endpoint be used for what I want to do? If yes, is there anything special to do to use this PATCH endpoint?
Thanks,
Axel
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect API
Tags:
App Store
App Store Connect
App Store Connect API
Hello,
I'm trying to remove a localization from a String Catalog in a Swift Package. How can I do that?
I tried to remove the file and create a new one, but all the languages are back. The only place where I've found a reference to the languages is in Package/.swiftpm/xcode/package.xcworkspace/xcuserdata/user.xcuserdatad/UserInterfaceState.xcuserstate
But I don't know how to edit this file to remove a language.
Thank you,
Axel
Hello,
When 'Ask To Buy' is enabled, and the user cancels the request (left button on the provided screenshot below), the purchaseResult in iOS 15 is set to .pending when we call try await product.purchase(). It's wrong, it should be set to .userCancelled because the parent will never receive any approval request in this case. It breaks the logic in my app because tracking real pending requests is then not possible.
I also think that a declined transaction should be made available to the app in the transactions observer: how can we remove a pending transaction that had been declined? We can't for the moment.
Thanks,
Axel
Hello,
I want to access the latest transaction for a Subscription Group. I use the following method static func status(for groupID: String) async throws -> [Product.SubscriptionInfo.Status] to access the statuses for the group, and from there, I can get a verified transaction from the status.
But when I set the GroupID equal to the Subscription Group Reference Name I put in the .storekit configuration file in Xcode, I don't have any status (so wrong ID). Actually, I have to use a subscriptionGroupID like 3F19ED53 (found using a previous transaction: https://developer.apple.com/documentation/storekit/transaction/3749718-subscriptiongroupid).
When I look into a Product, this ID is set for subscriptionFamilyId.
So my question is how can I know the ID if it's not the one I provided in App Store Connect or the config file? Do I first have to access a Product from this group?
Thanks.
Let's imagine an app with two plans, one for individual (level of service 2) and one for family (level of service 1).
If a user is subscribed as an individual, but if someone in his family shares a family plan with him, will Transaction.currentEntitlements show both subscriptions?
Or only the transaction where the user is the owner (in this case the individual subscription)?
When we request the current entitlements for a user using the Transaction.currentEntitlements static method, does StoreKit provide transactions for subscriptions with a Product.SubscriptionInfo.RenewalState set to .inGracePeriod or only .subscribed?
I'm asking because as a developer we need to give access to content to a user if its subscription is in .inGracePeriod. So in my opinion, the user is still entitled to this subscription.
I've not found any information in the documentation, WWDC videos or Apple sample codes. The documentation explains
The latest transaction for each active auto-renewable subscription
Is .inGracePeriod considered an active subscription?
I’m currently migrating my app to use the concurrency model in Swift. I want to serialize Tasks to make sure they are executed one after the other (no paralellism). In my use case, I want to listen to notifications posted by the NotificationCenter and execute a Task every time a new notification is posted. But I want to make sure no previous task is running. It's the equivalent of using an OperationQueue with maxConcurrentOperationCount = 1.
For example, I’m using CloudKit with Core Data in my app and I use persistent history tracking to determine what changes have occurred in the store. In this Synchronizing a Local Store to the Cloud Sample Code, Apple uses an operation queue for handling history processing tasks (in CoreDataStack). This OperationQueue has a maximum number of operations set to 1.
private lazy var historyQueue: OperationQueue = {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
return queue
}()
When a Core Data notification is received, a new task is added to this serial operation queue. So if many notifications are received, they will all be performed one after the other one in a serial way.
@objc
func storeRemoteChange(_ notification: Notification) {
// Process persistent history to merge changes from other coordinators.
historyQueue.addOperation {
self.processPersistentHistory()
}
}
In this Loading and Displaying a Large Data Feed Sample Code, Apple uses Tasks to handle history changes (in QuakesProvider).
// Observe Core Data remote change notifications on the queue where the changes were made.
notificationToken = NotificationCenter.default.addObserver(forName: .NSPersistentStoreRemoteChange, object: nil, queue: nil) { note in
Task {
await self.fetchPersistentHistory()
}
}
I feel something is wrong in the second project as Tasks could happen in any order, and not necessarily in a serial order (contrary to the first project where the OperationQueue as a maxConcurrentOperationCount = 1).
Should we use an actor somewhere to make sure the methods are serially called?
I thought about an implementation like this but I’m not yet really comfortable with that:
actor PersistenceStoreListener {
let historyTokenManager: PersistenceHistoryTokenManager = .init()
private let persistentContainer: NSPersistentContainer
init(persistentContainer: NSPersistentContainer) {
self.persistentContainer = persistentContainer
}
func processRemoteStoreChange() async {
print("\(#function) called on \(Date.now.formatted(date: .abbreviated, time: .standard)).")
}
}
where the processRemoteStoreChange method would be called by when a new notification is received (AsyncSequence):
notificationListenerTask = Task {
let notifications = NotificationCenter.default.notifications(named: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator)
for await _ in notifications {
print("notificationListenerTask called on \(Date.now.formatted(date: .abbreviated, time: .standard)).")
await self.storeListener?.processRemoteStoreChange()
}
}
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
Core Data
wwdc21-10194
wwdc21-10017
wwdc21-10019