When using SwiftUI Previews in a Swift Packages, are PreviewProviders automatically removed from the package when archiving an app, as it is the case with a app, or not?
If not, how to deal with that?
I’m not sure we can use compiler directives like if DEBUG in packages, can we?
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hello,
My app uses Core Location to request for Points Of Interest near the user. I used the different APIs provided by Apple: MKLocalPointsOfInterestRequest, MKLocalSearch.Request and MKLocalSearchCompleter. They do not provide the same results at all, whereas the configurations for the requests are very similar.
The MKLocalPointsOfInterestRequest provides very few places (if any, sometimes The operation couldn’t be completed. (MKErrorDomain error 4.) The others give more results but not identical. The code for the different requests is provided below.
Is this the expected behaviour?
If no, have I missed something?
Is this a bug?
Thanks
PS: Tested on Xcode 14.3, iOS 16.0.
MKLocalPointsOfInterestRequest
let center: CLLocationCoordinate2DMake = CLLocationCoordinate2DMake(41.38891, 9.16205)
let poiRequest: MKLocalPointsOfInterestRequest = MKLocalPointsOfInterestRequest(center: coordinate, radius: 3_000)
poiRequest.pointOfInterestFilter = MKPointOfInterestFilter(including: [.beach])
let poiSearch: MKLocalSearch = MKLocalSearch(request: poiRequest)
let resultsPOI = try await poiSearch.start()
print(resultsPOI.mapItems.compactMap(\.name))
This give me the following result:
["Plage de Stagnolu"]
MKLocalSearch.Request
let center: CLLocationCoordinate2DMake = CLLocationCoordinate2DMake(41.38891, 9.16205)
let searchRequest: MKLocalSearch.Request = MKLocalSearch.Request()
searchRequest.region = MKCoordinateRegion(center: coordinate, latitudinalMeters: 4_000, longitudinalMeters: 4_000)
searchRequest.pointOfInterestFilter = MKPointOfInterestFilter(including: [.beach])
searchRequest.resultTypes = .pointOfInterest
searchRequest.naturalLanguageQuery = "beach"
let search: MKLocalSearch = MKLocalSearch(request: searchRequest)
let results = try? await search.start()
print(results.mapItems.compactMap(\.name))
This give me se following results.
["Plage du Petit Sperone", "Plage de 3 Pointes", "Plage de Saint-Antoine Bonifacio", "Plage de Fazzio", "Piantarella Beach", "Plage du Grand Sperone", "Capu Testagro", "Plage de Balistra", "Plage de Stagnolo", "Plage de Cala Longa", "Plage de La Tonnara", "Plage Porto Novo", "Plage de Sant\'Amanza", "Rena Majori", "Plage de Rondinara", "Plage de Santa Giulia", "Spiaggia Rena Bianca", "Plage De Roccapina", "Cala Spinosa", "Naracu Nieddu Beach", "Porto Cervo Beach", "Lido Dog Beach", "Plage de Figari", "Capocchia Du Purpu", "Spiaggia Zia Culumba"]
MKLocalSearchCompleter
func search(coordinate: CLLocationCoordinate2D) {
completer.region = MKCoordinateRegion(center: coordinate, latitudinalMeters: 4_000, longitudinalMeters: 4_000)
completer.pointOfInterestFilter = MKPointOfInterestFilter(including: [.beach])
completer.resultTypes = .pointOfInterest
completer.queryFragment = "beach"
}
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
print(completer.results.map(\.title))
}
This give me the following result:
["Porto Istana Beach", "Sandbanks Beach", "Spiaggia La Cinta", "Piantarella Beach", "Platja de la Barceloneta", "Whitstable Beach", "West Wittering Beach", "Cala Millor"]
I want to animate part of my View when a property on a Core Data object is updated. These Core Data objects are ObservableObject so when I update a property on the object using a binding (like a Toggle) or a Button, I expect it to animate. But it’s not working. If I toggle a boolean property on my object, there is no animation. If I change a Boolean value in a Button using a withAnimation block, it does not animated. If I do the same with an ObservableObject class (boolean is a Published property), the animation is respected. A workaround is to use another property (isFavoriteWrapped) and to call objectWillChange.send() manually in the property setter. But this feels wrong. The expected behaviour should be similar to what we see with the ObservableObject.
I opened a FB12174214.
See attached screenshots.
How can this design be reproduced in SwiftUI?
The capsules are positioned to represent the values. But the calculation needs to take into account the labels width.
I tried using a mix of Grid and custom Layout but I haven’t found a way… Any help would be appreciated!
Thanks
Hello,
I'm currently developing an app using SwiftData.
I want the app to use CloudKit to sync data, so I made sure all my model properties are optional.
I've defined a Codable enum as follows:
enum Size: Int, Codable {
case small
case medium
case large
}
I've defined a Drink SwiftData model as follows:
@Model
class Drink {
var name: String?
var size: Size?
init(
name: String? = nil,
size: Size? = nil
) {
self.name = name
self.size = size
}
}
In one of my Views, I want to use a @Query to fetch the data, and use a Predicate to filter the data. The Predicate uses the size enumeration of the Drink model. Here is the code:
struct DrinksView: View {
@Query var drinks: [Drink]
init() {
let smallRawValue: Int = Size.small.rawValue
let filter: Predicate<Drink> = #Predicate<Drink> { drink in
if let size: Size = drink.size {
return size.rawValue == smallRawValue
} else {
return false
}
}
_drinks = Query(filter: filter)
}
var body: some View {
List {
ForEach(drinks) { drink in
Text(drink.name ?? "Unknown Drink")
}
}
}
}
The code compiles, but when I run the app, it crashes with the following error:
Thread 1: Fatal error: Couldn't find \Drink.size!.rawValue on Drink with fields [SwiftData.Schema.PropertyMetadata(name: "name", keypath: \Drink.name, defaultValue: nil, metadata: nil), SwiftData.Schema.PropertyMetadata(name: "size", keypath: \Drink.size, defaultValue: nil, metadata: nil)]
How can I filter my data using this optional variable on the Drink model?
Thanks,
Axel
Hello,
I'm trying to create a subscription for one of my apps.
When I specify the Product ID yearly_3, I get the following error message: The Product ID you entered is already being used by another subscription.
This app does not have any other subscriptions with this Product ID.
But I have another app with a yearly_3 Product ID.
According to the official documentation, the Product ID is A unique ID specific to your app. So I thought it was possible to have the same Product ID between apps, but not for the same app.
What's the rule here?
Thanks,
Axel
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
Subscriptions
App Store Connect
In-App Purchase
Hello,
I've noticed the prices of my products in my Xcode synced StoreKit configuration are not updated when I change the price in App Store Connect. I tried to manually sync the file, to remove and add it again to my project but old initial prices are still used.
In the screenshot below, the price is currently $2.99 but the file still uses the initial price of $1.99. It makes testing a little bit painful because I'm never sure which product is being shown.
Is this a bug?
Is there a way to get the live production App Store prices be used instead of the starting prices?
I filed a feedback for this: FB17798486
Regards,
Axel
Topic:
Developer Tools & Services
SubTopic:
Xcode
Tags:
StoreKit Test
StoreKit
App Store Connect
Xcode
Hello,
I'm working on an application that requires the use of significant location changes and visits, in addition to region monitoring and standard continuous location delivery (foreground and background).
iOS 17 and iOS 18 introduced changes to how we can monitor distinct regions of interest (with CLMonitor) as well as receive location updates (with CLLocationUpdate).
But I couldn't find any information regarding how to work with
Significant location changes. Do we still need to create a location manager and call startMonitoringSignificantLocationChanges()? Where are the updates received in this case, in the locationManager(_:didUpdateLocations:) or in the liveUpdates async sequence?
Visits. Same question here, for visit monitoring to work, do we still have to create a location manager then call startMonitoringVisits()? Where are the visits being notified? Still in locationManager(_:didVisit:) or in the liveUpdates asynchronous sequence?
I just want to be sure I understand correctly how to use the updates, and if some features of Core Location still need to use a location manager and the delegate to receive the events.
Maybe additional CLCondition will be added to cover both of these technologies as it seems highly related to monitoring conditions (significant location change, and visit).
Thank you,
Axel
Hello,
I noticed the Product.SubscriptionInfo subscriptionPeriod (of type Product.SubscriptionPeriod) is different for the same product between StoreKit Testing in Xcode and the sandbox/App Store (production) environment.
For a “1 week” auto-renewable subscription, we get the following:
StoreKit Testing in Xcode: 1 week gives a subscriptionPeriod with value of 1 and a unit of Product.SubscriptionPeriod.Unit.week
Sandbox/App Store: 1 week gives a subscriptionPeriod with value of 7 and a unit of Product.SubscriptionPeriod.Unit.day
This created issues in my app because I used the localizedDescription of a Product.SubscriptionPeriod to display a text similar to “$4.99 per week”. This is what I obtain with the StoreKit Testing in Xcode, but in the Sandbox/App Store environment, it displays “$4.99 per day” (because the subscriptionPeriod is “7 Days” and the unit is then .day). Obviously, this is not what I wanted to display.
Other periods like “1 month”, “2 months”, “3 months”, “6 months, and “1 year”, the period provided by both StoreKit Testing and Sandbox/App Store correspond to the period unit specified in App Store Connect.
In addition, I want to report that for a weekly subscription/offer or a 2 weeks offer, Product.SubscriptionInfo.subscriptionPeriod or Product.SubscriptionOffer.period == .weekly or .everyTwoWeeks is always false.
We observe the following:
With Sandbox or App Store live production:
1 week, Product.SubscriptionInfo.subscriptionPeriod == .weekly is false (because it’s “7 days”)
1 week, Product.SubscriptionOffer.period == .weekly is false (because it’s “7 days”)
2 weeks (offer), Product.SubscriptionInfo.subscriptionPeriod == .everyTwoWeeks is false (because it’s “14 days”)
2 weeks (offer), Product.SubscriptionOffer.period == .everyTwoWeeks is false (because it’s “14 days”)
But with an Xcode StoreKit configuration file:
1 week, Product.SubscriptionInfo.subscriptionPeriod == .weekly is true (because it’s “1 week”)
1 week, Product.SubscriptionOffer.period == .weekly is true (because it’s “1 week”)
2 weeks, Product.SubscriptionInfo.subscriptionPeriod == . everyTwoWeeks is true (because it’s “2 weeks”)
2 weeks, Product.SubscriptionOffer.period == . everyTwoWeeks is true (because it’s “2 weeks”)
So in sandbox and production, .weekly and .everyTwoWeeks is never possible.
If someone from Apple could check the feedback FB19605865 🙂
Thank you
Regards,
Axel, @alpennec
Code:
do {
let productIDs: [String] = ["revenueSocks_weekly_trial"]
let products: [StoreKit.Product] = try await Product.products (for: productIDs)
let weeklySubscription: StoreKit.Product = products.first!
let displayPrice: String = weeklySubscription.displayPrice
// For a weekly subscription in App Store Connect
// With an Xcode StoreKit configuration file: subscriptionPeriod unit is Week (week), value is 1 → "1 Week"
// With the Sandbox + App Store: subscriptionPeriod unit is Day (.day), value is 7 → "7 Days"
let unitString: String = weeklySubscription.subscription!.subscriptionPeriod.unit.localizedDescription
print("\(displayPrice) per \(unitString.localizedLowercase)")
// StoreKit configuration file → "$4.99 per week"
// Sandbox + App Store → "$4.99 per day"
} catch {
print(error)
}
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
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