Post

Replies

Boosts

Views

Activity

SwiftData: Predicate using optional Codable enum
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
0
3
662
Oct ’24
Clear Purchase History for a Sandbox Apple ID doesn't work
Hello, I'm trying to clear the purchase history made with a sandbox Apple ID on my test device but it does not work. The past purchases are still returned by StoreKit. I've waited many hours but it seems to persist. When I use for await result in Transaction.currentEntitlements { in my app, my non-consumable product is still here. Is it expected? How long should it take to reset the history? Is is supposed to work also for non-consumable products? Thanks Axel
4
10
1.1k
Sep ’24
Automatic Grammar Agreement with formatted number: use integer value to switch categories
Hello, I want to use Automatic Grammar Agreement to localise a string in my app, let say "three remaining activities". The string "three" is obtained by using a NumberFormatter with a numberStyle set to .spellOut (so I'm not using an Integer) var formatter: NumberFormatter = NumberFormatter() formatter.numberStyle = .spellOut let formattedCount: String = numberFormatter.string(from: count as NSNumber)! Text("key_with_string_\(formattedCount)") In my string catalog, I have translated the key key_with_string_%@ like this ^[%@ remaining activity](inflect: true), but it does not work. I've tried to add the integer value used by the number formatter in the key key_with_string_%@_%lld but it does not work. Should Automatic Grammar Agreement work normally just by using the formatted string provided by the NumberFormatter? If not, is there a way to specify to use a secondary variable (my count integer) to switch between different categories like one and other automatically? Thanks ! Axel
1
0
883
Jun ’24
SwiftUI: detect the beginning of a View using scrollPosition in a V/HStack
Hello, I want to detect when a ScrollView is scrolled at the top of a specific View in a LazyVStack. Here is the code I use: struct ContentView: View { @State private var scrollID: Int? var body: some View { HStack { VStack { Text(scrollID?.formatted() ?? "Unknown") Button("Go") { withAnimation { scrollID = 7 } } Divider() ScrollView { LazyVStack(spacing: 300) { ForEach(0...100, id: \.self) { int in Text(int.formatted()) .frame(maxWidth: .infinity) .background(.red) } } .scrollTargetLayout() } .scrollPosition(id: $scrollID, anchor: .top) } } } } As I specify a top anchor, I was expecting to see the scrollID binding being updated when the red Text View is at the top of the ScrollView. But I noticed that scrollPosition updates the binding way before the red Text View is positioned at the top of the ScrollView, which is not what I want. In this image, you can see the binding is already at one even though there is a lot of space between the View and the top of the ScrollView. Maybe the Stack spacing is taken into account? And manually setting the binding scroll at the position I want, just above the red Text for 7, which makes me think the views IDs are correct. Is my understanding wrong about this modifier? How can I detect the top (beginning) of the View? (If this is a SwiftUI bug, I filed #FB13811349)
4
0
2.7k
Jun ’24
How does listSectionSpacing works in SwiftUI?
Hello, I want to understand how listSectionSpacing with a custom CGFloat value works in SwiftUI. According to the documentation, we can use different spacing between sections and If adjacent sections have different spacing value, the smaller value on the shared edge is used. For example, if I have a: Section A with a listSectionSpacing of 10 Section B with a listSectionSpacing of 200 Section C with a listSectionSpacing of 20 Section D with a listSectionSpacing of 0 I notice the spacing between the sections A+B and B+C is none of 10, 200 or 20. If the documentation is correct, shouldn't it be 10? If I now have a: Section A with a listSectionSpacing of 200 Section B with a listSectionSpacing of 200 Section C with a listSectionSpacing of 200 Section D with a listSectionSpacing of 0 I notice the spacing is never 200. Is the spacing capped? Also, if I specify a header and footer, the spacing doesn't seem to be used at all. Thus the spacing is the same for all sections. Is my understanding wrong and this API working as expected? Or is that a bug in how the spacing is used? I filed #FB13699952 few weeks ago. Axel struct ListSections: View { @State private var header: Bool = false @State private var footer: Bool = false private let sections: [ListSection] = [ ListSection(position: "A", spacing: 200), ListSection(position: "B", spacing: 200), ListSection(position: "C", spacing: 200), ListSection(position: "D", spacing: 0) ] var body: some View { VStack { Toggle("Header", isOn: $header) Toggle("Footer", isOn: $footer) } .padding(.horizontal) List { ForEach(sections) { section in Section { LabeledContent("Section \(section.position)", value: section.spacing.formatted()) } header: { if header { Text("Header \(section.position)") .background(.red.opacity(0.3)) } } footer: { if footer { Text("Footer \(section.position)") .background(.green.opacity(0.3)) } } .listSectionSpacing(section.spacing) } } } } #Preview { ListSections() }
Topic: UI Frameworks SubTopic: SwiftUI
7
0
1.6k
Jun ’24
Are Privacy Nutrition Labels in App Store Connect automatically updated based on Privacy Manifest files in the app and third-party SDKs?
Hello, I include a Privacy Manifest file in my app and specify one Privacy Nutrition Label Type (Email Address, for marketing purposes). My app uses some third-party SDKs like RevenueCat that contain Privacy Manifest files with nutrition label types specified (Purchases History for RevenueCat for example). Xcode can generate a report that aggregates all the data types that are collected by the app. But is App Store Connect updated when I upload a build? Or do I have to manually setup the App Privacy info? Thanks
1
0
746
Jun ’24
SwiftUI Map: is it possible to add an inset to the map visible rectangle?
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?
2
0
1.8k
Feb ’24
NavigationSplitView crashes if I select an item in the sidebar after I removed other items
My NavigationSplitView crashes if I select an item in the sidebar after I removed other items: Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1c44d488c) How to reproduce: Launch the app from the attached project: https://gist.github.com/alpennec/a45f5ff94382dc922718906a60a35220 Tap on “Add” Select the new added item in the sidebar In the detail view, tap “Delete” Select “All” in the sidebar The app crashes: Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1c44d488c) It occurs if I use just Strings or Core Data objects (I tried with plain String because I thought it was maybe an issue with Core Data but it’s not apparently). What is wrong? Is that a bug? Filed #FB13561900 for this.
3
0
847
Jan ’24
Calendar nextDate/enumerateDates methods with backward direction does not work for September
I’m trying to get the previous date that matches the 9nth month in the Gregorian calendar (which is September) from Date.now (which is in December 2023 right now). The expected date is then in 2023. The first date returned is in 1995. Why? I filed the feedback FB13462533 var calendar: Calendar = Calendar(identifier: .gregorian) calendar.timeZone = TimeZone.autoupdatingCurrent let matchingDateComponents: DateComponents = DateComponents(month: 09) let date: Date? = calendar.nextDate( after: Date.now, matching: matchingDateComponents, matchingPolicy: .nextTime, direction: .backward ) print(date) // Optional(1995-08-31 23:00:00 +0000)
4
0
730
Dec ’23
In Swift, how can I get the "last Sunday of a month before the current date"?
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?
2
0
1k
Dec ’23
SwiftUI + Core Data: animation on Core Data object properties does not work.
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.
0
0
1.1k
May ’23
MKLocalPointsOfInterestRequest does not return the same results than MKLocalSearch.Request or MKLocalSearchCompleter
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"]
0
2
1.4k
Apr ’23
Swift Package and SwiftUI Previews: are PreviewProviders automatically removed when the package is compiled?
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?
0
0
915
Feb ’23