Post

Replies

Boosts

Views

Activity

Reply to Pass @Query filter predicate from parent view in SwiftData
The current approach for this would be to move the initialisation of the query to the view's initialiser. Something like this will work: struct ScoreListView: View { @Query private var items: [SWDItem] let selectedPackage: SWDItem init(selectedPackage: SWDItem) { self.selectedPackage = selectedPackage _items = Query(filter: #Predicate<SWDItem> { item in item.package?.id == selectedPackage.id }, sort: \.timestamp) } var body: some View { ... } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to Set initial position on scrollable bar chart?
You can use this to set the initialX value to the 7th-from-the-end element of the stepDays array. .chartScrollPosition(initialX: stepDays[stepDays.index(stepDays.endIndex, offsetBy: -7, limitedBy: stepDays.startIndex) ?? stepDays.startIndex].weekDay) This also prevents you getting index out of range errors if the length of the array is less than 7.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to Pass @Query filter predicate from parent view in SwiftData
You must remember that we are only in the second beta of SwiftData and there are loads of bugs still floating around at the moment. I just had a quick look at the release notes for beta 2 and look what I found: SwiftData Known Issues • #Predicate does not support UUID, Date, and URL properties. (109539652) So the problem is definitely with the predicate and the fact that you are comparing UUID properties.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to 'init(coordinateRegion:i.... was deprecated in iOS 17.0
Those tutorials were built for Xcode 13.1 (iOS 15) and so aren't updated to use new APIs introduced with later releases, including the new SwiftUI MapKit updates. If you want to proceed with the new APIs, I'd recommend watching these session videos from WWDC23: What's new in SwiftUI Meet MapKit for SwiftUI and having a look at the documentation to see what's changed. Now to convert your "old" code to use the new MapKit APIs. As there is no direct conversion, this was the best I could come up with. struct MapView: View { @State private var region = MKCoordinateRegion() let initialPosition: MapCameraPosition = { let center = CLLocationCoordinate2D(latitude: 34.011_284, longitude: -116.166_860) let span = MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2) let region = MKCoordinateRegion(center: center, span: span) return .region(region) }() var body: some View { Map(initialPosition: initialPosition) .onMapCameraChange(frequency: .continuous) { context in region = context.region } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to Binding with ForEach or List doesn't work anymore when using @Observable macro
To get bindings from an Observable class, you need to use the @Bindable property wrapper as normal. However, the bindable value is coming from the environment so this is different. Whether this solution is a workaround or the intention going forward, it works nonetheless. var body: some View { @Bindable var library = library // place in view body List($library.books) { $book in BookView(book: book) } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to I need help with the depreciated code
Check out the Migrating to new navigation types article to see how SwiftUI's navigation APIs changed. New in iOS 17 is a modifier that seems to be a replacement for the tag-selection navigation link behaviour: navigationDestination(item:destination:). Something like this could work: var body: some View { NavigationStack { // change here VStack { List(forms, id: \.self) { form in // use new navigation link with a value NavigationLink(value: form) { Text(form) } } // add new modifier .navigationDestination(item: formBinding()) { form in formView(for: form) } } } } private var formBinding() -> Binding<String?> { // remove unused parameter Binding<String?>( get: { selectedForm }, set: { newValue in if newValue != selectedForm { selectedForm = newValue isFormSelected = newValue != nil } } ) }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to How to form a search predicate using swift data with a one to many model
"Cannot convert value of type 'Bool?' to closure result type 'Bool'" This is a simple Swift error. In your filter expression you are using optional chaining which is why it yields a result of type Bool?. The predicate closure, however, expects to be given a value of type Bool. Here is a fix for that particular error: let searchPredicate = #Predicate<SectionsSD> { $0.toArticles?.contains(filter) == true } ‎ "Instance method 'contains' requires the types 'ArticlesSD' and 'String.Element' (aka 'Character') be equivalent" $0.articles is of type [ArticlesSD]? and using contains on this array means you need to pass it a value of type ArticlesSD to check for. You are instead passing it a String (I'm assuming here that filter is a String) which is not what it expects. To fix this you can compare the filter to the search property in the contains closure. let searchPredicate = #Predicate<SectionsSD> { $0.toArticles?.contains { $0.search.contains(filter) } == true } And now you may think this works…but it doesn't. Swift spits out this error: "Optional chaining is not supported here in this predicate. Use the flatMap(_:) function explicitly instead. (from macro 'Predicate')". To fix this you can do what it says and wrap the original condition inside of a flatMap, like this: let searchPredicate = #Predicate<SectionsSD> { $0.toArticles.flatMap { $0.contains { $0.search.contains(filter) } } == true } Hope this helps (and works)!
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to Customizing Selection Highlight Color for NavigationLink in NavigationSplitView
Just a note: the accentColor(_:) modifier is deprecated and the AccentColor in the Assets catalogue or the tint(_:) modifier should be used instead. First of all, make sure you have your System Settings > Appearance > Accent Colour set to "Multicolour" to allow different colours for apps' accent colours. By default, sidebar list items take on the app's accent colour (defined in the Assets catalogue). This is where your app's accent colour should go anyway. If it is defined in code, like you are doing, you could use the tint(_:) modifier instead, but I don't know if this method works.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to Print amount from single member instance on dynamic view
First of all, you need a way for the SingleMember view to communicate to the MainView and vice versa – a two-way communication. You can achieve this with the @Binding property wrapper. It can be used like this: struct SingleMember: View { @Binding var text: String var body: some View { TextField("Amount", text: $text) } } You then need to create a source-of-truth for those three values in the parent MainView that can also be passed to the child SingleMember views. You can either create three separate variables or an array of values depending on whether 3 is a fixed value or not. The binding can be created and passed around like this: struct MainView: View { @State private var values: [String] = .init(repeating: "", count: 3) var body: some View { VStack { ForEach(0..<3) { i in SingleMember(text: $values[i]) } Button("Print all values") { print(values) } } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to How to form a search predicate using swift data with a one to many model
Thank you for this. I decided to check whether the logic of the predicate expression was wrong or the #Predicate itself was doing something, and it turns out it's the latter. Instead of filtering the sections within the query, I moved it outside to the regular place filtering happens. This works as expected with the sections being filtered correctly by the filter text. @Query private var sections: [SectionsSD] let filter: String var filteredSections: [SectionsSD] { sections.filter { $0.toArticles.flatMap { $0.contains { $0.search.contains(filter) } } == true // or as before // $0.toArticles?.contains { $0.search.contains(filter) } == true } } List(filteredSections) { ... } So it's when placed inside the #Predicate are things not working. It is definitely worth noting that we are only in the second beta of SwiftData so there is always the chance things don't work because of internal bugs. For example, in the release notes is this which could be the reason your predicate isn't working. SwiftData Known Issues • SwiftData queries don't support some #Predicate flatmap and nil coalescing behaviors. (109723704) It's best to wait for the next few betas to see if anything changes, and maybe new features might make things easier.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to Can't figure out why nothing conforms to "View"
Xcode/Swift like sending you in different directions with errors messages, but this one I'm sure is easier to solve. The issue is not with the ToolbarItemGroup but with the Label in the ToolbarItem. ToolbarItem(placement: .principal) { Label("hi") // error is here } Label requires two arguments and you have only passed it one. Either change it to a Text view or provide the second parameter, either systemImage: or image:.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to How to form a search predicate using swift data with a one to many model
My initial thought for this was to use something similar to @SectionedFetchRequest: get all the articles, filter them down, then group by section. At the moment SwiftData doesn't have that capability. I did file feedback for this (FB12292770) so hopefully this is possible later on and could be a solution for your problem. Sectioning would be more efficient because you are currently filtering twice, one for the sections' articles and then again for the articles in each section, when you could do it all at once including a predicate. ‎ "No exact matches in reference to static method 'buildExpression'" This normally means that there is an error somewhere else in the view code but you just need to find it. Try commenting out certain bits to see where the actual error is located. My guess, by looking at your code, is that you are applying the .listRowSeparator(.hidden) to the if statement and not an actual view. ‎ I have noted that you are force unwrapping result.toArticles!. Maybe you could remove the optional and give it a default value instead if you are confident it won't be nil. var toArticles: [ArticlesSD] = [] This might eliminate some of the optionality problems encountered with the predicate.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to SwiftData Query relationships not working
The problem is with your predicate. let filter = #Predicate<Student> { student in student.department?.id == departmentID // <- here } You are comparing two UUID properties and, according to the beta 2 release notes, it doesn't like this. SwiftData Known Issues • #Predicate does not support UUID, Date, and URL properties. (109539652)
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jul ’23
Reply to NavigationPath doesn't work with the @Observable macro iOS 17
With the new Observation APIs in SwiftUI, you no longer need to use @StateObject to initialise the observable objects. You also don't need to use @State like you are doing. You can simply do this: let navigationModel = NavigationModel() The Observable macro does the rest. However, the NavigationStack requires a binding to a path and your navigationModel object cannot provide one. There is a solution and that is through the @Bindable property wrapper, used like this: @Bindable var navigationModel = NavigationModel() Now you can get bindings from properties within that object.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jul ’23