I'm trying to use Previews in a Swift Package in Xcode 14b2 but it's not working (it was working in Xcode 13). I have the following error message but I don't know how to solve it.
"XCPreviewAgent.app" must be code signed in order to use on-device previews. Check your code signing settings for the target.
com.apple.dt.UVPreviewAgent-watchOS.watchkitapp {
url: file:///Applications/Xcode-beta.app/Contents/Developer/Platforms/WatchOS.platform/Developer/Library/Xcode/Agents/XCPreviewAgent.app
version: 20.0.32.2
attributes: [
ObjectIdentifier(0x00000001638e5d18): ["OS_ACTIVITY_DT_MODE": "YES", "SQLITE_ENABLE_THREAD_ASSERTIONS": "1"],
]
}
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()
}
}
Xcode Version 13.3 beta 3 (13E5104i) or Version 13.2.1
(13C100)
When I add a dictionary to the Info.plist file from the Info tab in the project (for example with the Privacy - Location Temporary Usage Description Dictionary key), Xcode immediately crashes with the following message, that seems to be related to the type of new item added.
ASSERTION FAILURE in /Library/Caches/com.apple.xbs/Sources/DVTFrameworks/DVTFrameworks-20084/DVTFoundation/MacroExpansion/DVTMacroDefinitionTable.mm:1034
Details: value must be nil, string or array, but is {
}
Object: <DVTMacroDefinitionTable: 0x7fe3afb62ce0>
Method: -_setLiteralValue:forMacroName:conditionSet:wantsCheckForDVTMacroExpansionConformance:
Thread: <_NSMainThread: 0x7fe3c480ed70>{number = 1, name = main}
Open FDs: 70/7168
Hints:
Backtrace:
0 -[IDEAssertionHandler handleFailureInMethod:object:fileName:lineNumber:assertionSignature:messageFormat:arguments:] (in IDEKit)
1 _DVTAssertionHandler (in DVTFoundation)
2 _DVTAssertionFailureHandler (in DVTFoundation)
3 -[DVTMacroDefinitionTable _setLiteralValue:forMacroName:conditionSet:wantsCheckForDVTMacroExpansionConformance:] (in DVTFoundation)
4 -[DVTMacroDefinitionTable setLiteralValue:forMacroName:conditionSet:] (in DVTFoundation)
5 -[DVTMacroDefinitionTable setObject:forKeyedSubscript:] (in DVTFoundation)
6 __52-[PBXTarget _adjustBuildSettingsForProductSettings:]_block_invoke (in DevToolsCore)
7 __NSDICTIONARY_IS_CALLING_OUT_TO_A_BLOCK__ (in CoreFoundation)
8 -[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:] (in CoreFoundation)
9 -[PBXTarget _adjustBuildSettingsForProductSettings:] (in DevToolsCore)
10 -[PBXTarget writeProductSettings:configuration:] (in DevToolsCore)
11 -[PBXTarget setProductSettings:configuration:] (in DevToolsCore)
12 -[PBXTarget setProductSettings:] (in DevToolsCore)
13 -[Xcode3ExtensionBasedInfoController setInfoDictionary:] (in Xcode3UI)
14 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] (in Foundation)
15 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] (in Foundation)
16 _NSSetObjectValueAndNotify (in Foundation)
17 __35-[Xcode3InfoEditor _createSubviews]_block_invoke (in Xcode3UI)
18 -[DVTObservingBlockToken observeValueForKeyPath:ofObject:change:context:] (in DVTFoundation)
19 NSKeyValueNotifyObserver (in Foundation)
20 NSKeyValueDidChange (in Foundation)
21 NSKeyValueDidChangeWithPerThreadPendingNotifications (in Foundation)
22 -[Xcode3InfoDictionarySliceController _mergeInfoDictionaries] (in Xcode3UI)
23 -[Xcode3InfoDictionarySliceController customPlistChanged:] (in Xcode3UI)
24 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ (in CoreFoundation)
25 ___CFXRegistrationPost_block_invoke (in CoreFoundation)
26 _CFXRegistrationPost (in CoreFoundation)
27 _CFXNotificationPost (in CoreFoundation)
28 -[NSNotificationCenter postNotificationName:object:userInfo:] (in Foundation)
29 -[Xcode3InfoEditorPlistDocument propertyListChanged:] (in Xcode3UI)
30 -[DVTPlistModel _setPlistNoCopy:forKeyPath:atIndex:doReplace:doNotify:] (in DVTKit)
31 -[DVTPlistModel setKey:forPlist:] (in DVTKit)
32 -[DVTPlistModel setLocalizedKey:forPlist:] (in DVTKit)
33 -[DVTPlistViewController outlineView:setObjectValue:forTableColumn:byItem:] (in DVTKit)
34 -[NSOutlineView _dataSourceSetValue:forColumn:row:] (in AppKit)
35 -[NSTableView _setNewObjectValueFromCell:ifNotEqualTo:forTableColumn:row:] (in AppKit)
36 -[NSTableView textDidEndEditing:] (in AppKit)
37 -[DVTPlistOutlineView textDidEndEditing:] (in DVTKit)
38 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ (in CoreFoundation)
39 ___CFXRegistrationPost_block_invoke (in CoreFoundation)
40 _CFXRegistrationPost (in CoreFoundation)
41 _CFXNotificationPost (in CoreFoundation)
42 -[NSNotificationCenter postNotificationName:object:userInfo:] (in Foundation)
43 -[NSTextView(NSSharing) resignFirstResponder] (in AppKit)
44 -[NSWindow _realMakeFirstResponder:] (in AppKit)
45 -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] (in AppKit)
46 -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] (in AppKit)
47 -[NSWindow(NSEventRouting) sendEvent:] (in AppKit)
48 -[IDEWorkspaceWindow sendEvent:] (in IDEKit)
49 -[NSApplication(NSEvent) sendEvent:] (in AppKit)
50 -[IDEApplication sendEvent:] (in IDEKit)
51 -[NSApplication _handleEvent:] (in AppKit)
52 -[NSApplication run] (in AppKit)
53 -[DVTApplication run] (in DVTKit)
54 NSApplicationMain (in AppKit)
55 start (in dyld)
ProductBuildVersion: 13E5104i
abort() called
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
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?
When dealing with auto-renewable subscriptions, there are multiple ways to access the latest transaction. We can access it when a purchase is made, or we can request the latest transaction for a given productID at a later time. To do so, we can use Transaction.latest(for:), access the transaction history using Transaction.all, get the currentEntitlements, or use the array of Product.SubscriptionInfo.Statusthan contains the latest transaction for a subscription group. It's also necessary to listen to transactions when the app is running using the AsyncSequenceTransaction.updates`.
In my app (and also in the SKDemo project from Apple), when I want to access the latest transaction as soon as the app is launched, it's missing the transactions that renewed or happened while the app was not running. I tried using the different methods mentioned above but they never give me the latest transaction, always the latest transaction while the app was running before I killed it. I have to wait for a new renewal event to receive the latest transaction in the Transaction.updates listener, which is not good. For example, when I set the Subscription Renewal Rate to Monthly Renewal Every 30 seconds, and I quit the app when the latest transactionId is 100, I wait for 5 minutes, I expect to see the transactionId 110 but I see 100. In the real life, it means that if the app is not running when a monthly or annual subscription renews, I have to wait weeks or months to receive the missing transaction. I thought that the Transaction.updates listener would be called at launch with all the transactions that occurred while the app was not running.
Is that a bug in Xcode or have I misunderstood something? How can I access the real latest transaction that happened when the app was not running at launch? I need to access that to know what the user has access to. I think the transaction management panel from Xcode displays all the transactions, even the one when the app was not running.
PS: I'm using Xcode 13.2.1 and iOS 15.0 (simulator). Transaction.updates is not working on iOS 15.2 (my device, or simulator) from what I've seen so far.
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)
}
}
I'm not a member of any Family in iCloud. I want to understand what happens when a user is subscribed through Family Sharing but also how to use StoreKit when the user is subscribed twice: as an individual who purchased the product and as a member of a family when the purchase is shared with him.
How can I test Family Sharing for an app offering a product with Family Sharing enabled? Is it possible to create a fake Family in App Store Connect and add testers to it?
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)?
Hello,
When a user cancels a subscription during a free trial, we should stop providing access to content. How can we know that? From the in app management in Xcode, when I cancel a subscription during free trial period (cancelling in the few seconds after the purchase), the currentEntitlements still provide the subscription.
How to know when a user cancelled the subscription during free trial?
Thanks
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.
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'm currently adding StoreKit 2 into my app. I've watched the WWDC21 session (Meet SK2) and downloaded the sample SKDemo app. When I want to test the Ask To Buy flow, it does not work: I see the sheet on the device, I see the alert and tap on the "Ask" button. In Xcode, I then approve the transaction but the func listenForTransactions() -> Task<Void, Error> is never called. I'm testing the app in Debug mode, on a real device and on a simulator (using the Products.storekit local configuration file).
What's wrong?
Thanks,
Axel
Version 13.2 beta 2 (13C5081f)
iOS 15.2 (19C5044b)
func listenForTransactions() -> Task<Void, Error> {
return Task.detached {
for await result in Transaction.updates {
do {
let transaction = try self.checkVerified(result)
await self.updatePurchasedIdentifiers(transaction)
await transaction.finish()
} catch {
print("Transaction failed verification")
}
}
}
}
I have two entities in my app: User & Expense. A user has many expenses. Expense as an attribute amount (of type Int32).
I added a derived attribute expensesCount (of type Int16) on the user to count the number of expenses, using the derivation expenses.@count. It's working fine, the app compiles, launches, and when I save a relationship, the value for the expensesCount attribute is updated.
I also added a derived attribute expensesAmount on the user to count the total amount of all related expenses. I use the derivation expenses.amount.@sum. The app compiles but crash at launch with the following error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'currently unsupported (unsupported function on to many (not count or sum))'
Any idea why?
PS: I also tried another synthax recommended on Twitter (by Scott Perry from Apple team): sum:(expenses.amount), but I got the same crash.
Like in a lot of apps, I have a list of items (populated by a Core Data fetch request), a sheet to create new items, and a sheet to edit an item when tapping on a row in my list. I'm trying to unify both forms to create and edit an update, and put the cancel / save logic in a superview of the form.
So I've something like this:
ListView: a list with row populated by a Core Data fetch request
AddView: a NavigationView with the FormView embed + cancel and save button
EditView: a NavigationView with the FormView embed + cancel and save button
FormView: a TextField to update the name of the item
In the init() for the AddView, I create a new NSManagedObject without any context (I do that because I don't want my ListView to be updated when I create a new item in the AddView, but only when I save this item -> alternative could be to use a child context, or filter the fetch request results based on the isInserted or objectID.isTemporaryID of the return objects). AddView contains a NavigationView with the FormView embed, a cancel button, and a save button. This save button is disabled based on a computed property on the managed object (name for the object can't be nil).
In the EditView, I pass the item that was tapped from the ListView. This item is an existing NSManagedObject attached to the main viewContext of the app (coming from the fetch request of the ListView). EditView contains a NavigationView with the FormView embed, a cancel button and a save button (exactly like the AddView). This save button is also disabled based on the same computed property.
My issue is that when I update the name of the item from the TextField in my FormView, the condition to enable / disable the save button is not working for the AddView (this AddView is actually not refreshed when I change the item name from the FormView) but working for the EditView (this EditView is refreshed when I change the item name from the FormView). If I attach a context to the new NSManagedObject in the init() of the AddView, the condition is working like in the EditView.
So it appears that a NSManagedObject without any context is not observed by SwiftUI? Am I missing anything or is that a bug?