Post

Replies

Boosts

Views

Activity

Reply to Is there a Plug In or SwiftUI Kit for changing measurements
The Foundation framework has built-in support for measurements and conversions. Here are some examples of how you can use the Measurement type and convert between different units: // Yards to Metres let yardsValue = Measurement(value: 50, unit: UnitLength.yards) let metresValue = yardsValue.converted(to: .meters) // Pints to Litres let pintsValue = Measurement(value: 10, unit: UnitVolume.pints) let litresValue = pintsValue.converted(to: .liters) // Pounds to Kilograms let poundsValue = Measurement(value: 100, unit: UnitMass.pounds) let kilogramsValue = poundsValue.converted(to: .kilograms)
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to Missing parameter error in the first couple of steps
The session video you're referring to is from WWDC23, so it is using the new APIs introduced. The Map struct with the initialiser you are trying to use is only available from iOS 17 and aligned releases. To use these new features you will have to update to Xcode 15. In the meantime, use one of the old (marked as deprecated) initialisers that work in Xcode 14.3.1.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to How to perform an action based on the local time?
Your code doesn't work because of the way dates are created. Through your extension on Date, you are creating one from a string in the format of "HH:mm:ss" (hours, minutes, seconds). That is all the data the date has in order to be created so other values, such as day, month, year, are filled in from the reference date (00:00:00 UTC on 1 January 2001). In your case, the breakfast date is "01/01/2000 00:00:01". However, the now date has other date components (day, month, year…) provided and so won't be between two dates 23 years ago. With the code you have, you can just change the way you create the now variable like this: var now = Date.parse(Date().dateString()) This extracts the provided components in the format string from the current date using your extensions on Date.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
Reply to Navigation Link Syntax
Converting your example code to use the new APIs would look like this: NavigationStack { Button { isNavigating = true } label: { Text("Don't have an account? Sign Up") .foregroundColor(.blue) } .navigationDestination(isPresented: $isNavigating) { SignUpView() } } There is a lot more that can be done with NavigationLink and the navigationDestination modifier so I suggest you look at the documentation to see what else there is. You can also watch the What's new in SwiftUI and The SwiftUI cookbook for navigation session videos from WWDC22 as well as read the Migrating to new navigation types article for more details.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jun ’23
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 Is there a Plug In or SwiftUI Kit for changing measurements
The Foundation framework has built-in support for measurements and conversions. Here are some examples of how you can use the Measurement type and convert between different units: // Yards to Metres let yardsValue = Measurement(value: 50, unit: UnitLength.yards) let metresValue = yardsValue.converted(to: .meters) // Pints to Litres let pintsValue = Measurement(value: 10, unit: UnitVolume.pints) let litresValue = pintsValue.converted(to: .liters) // Pounds to Kilograms let poundsValue = Measurement(value: 100, unit: UnitMass.pounds) let kilogramsValue = poundsValue.converted(to: .kilograms)
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Jun ’23
Reply to Missing parameter error in the first couple of steps
The session video you're referring to is from WWDC23, so it is using the new APIs introduced. The Map struct with the initialiser you are trying to use is only available from iOS 17 and aligned releases. To use these new features you will have to update to Xcode 15. In the meantime, use one of the old (marked as deprecated) initialisers that work in Xcode 14.3.1.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Jun ’23
Reply to How to perform an action based on the local time?
Your code doesn't work because of the way dates are created. Through your extension on Date, you are creating one from a string in the format of "HH:mm:ss" (hours, minutes, seconds). That is all the data the date has in order to be created so other values, such as day, month, year, are filled in from the reference date (00:00:00 UTC on 1 January 2001). In your case, the breakfast date is "01/01/2000 00:00:01". However, the now date has other date components (day, month, year…) provided and so won't be between two dates 23 years ago. With the code you have, you can just change the way you create the now variable like this: var now = Date.parse(Date().dateString()) This extracts the provided components in the format string from the current date using your extensions on Date.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Jun ’23
Reply to Navigation Link Syntax
Converting your example code to use the new APIs would look like this: NavigationStack { Button { isNavigating = true } label: { Text("Don't have an account? Sign Up") .foregroundColor(.blue) } .navigationDestination(isPresented: $isNavigating) { SignUpView() } } There is a lot more that can be done with NavigationLink and the navigationDestination modifier so I suggest you look at the documentation to see what else there is. You can also watch the What's new in SwiftUI and The SwiftUI cookbook for navigation session videos from WWDC22 as well as read the Migrating to new navigation types article for more details.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Jun ’23
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:
Replies
Boosts
Views
Activity
Jun ’23
Reply to SwiftUI: Bottom sheet from the iPhone "find my" and "maps" app
With iOS 16.4 you now can by using the new presentationBackgroundInteraction(_:) modifier. For your case you can apply this to your presented view: .presentationBackgroundInteraction(.enabled)
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
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:
Replies
Boosts
Views
Activity
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:
Replies
Boosts
Views
Activity
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:
Replies
Boosts
Views
Activity
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:
Replies
Boosts
Views
Activity
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:
Replies
Boosts
Views
Activity
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:
Replies
Boosts
Views
Activity
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:
Replies
Boosts
Views
Activity
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:
Replies
Boosts
Views
Activity
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:
Replies
Boosts
Views
Activity
Jun ’23