Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

.fileImporter not working on iPhone
I've been running into an issue using .fileImporter in SwiftUI already for a year. On iPhone simulator, Mac Catalyst and real iPad it works as expected, but when it comes to the test on a real iPhone, the picker just won't let you select files. It's not the permission issue, the sheet won't close at all and the callback isn't called. At the same time, if you use UIKits DocumentPickerViewController, everything starts working as expected, on Mac Catalyst/Simulator/iPad as well as on a real iPhone. Steps to reproduce: Create a new Xcode project using SwiftUI. Paste following code: import SwiftUI struct ContentView: View { @State var sShowing = false @State var uShowing = false @State var showAlert = false @State var alertText = "" var body: some View { VStack { VStack { Button("Test SWIFTUI") { sShowing = true } } .fileImporter(isPresented: $sShowing, allowedContentTypes: [.item]) {result in alertText = String(describing: result) showAlert = true } VStack { Button("Test UIKIT") { uShowing = true } } .sheet(isPresented: $uShowing) { DocumentPicker(contentTypes: [.item]) {url in alertText = String(describing: url) showAlert = true } } .padding(.top, 50) } .padding() .alert(isPresented: $showAlert) { Alert(title: Text("Result"), message: Text(alertText)) } } } DocumentPicker.swift: import SwiftUI import UniformTypeIdentifiers struct DocumentPicker: UIViewControllerRepresentable { let contentTypes: [UTType] let onPicked: (URL) -> Void func makeCoordinator() -> Coordinator { Coordinator(self) } func makeUIViewController(context: Context) -> UIDocumentPickerViewController { let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true) documentPicker.delegate = context.coordinator documentPicker.modalPresentationStyle = .formSheet return documentPicker } func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {} class Coordinator: NSObject, UIDocumentPickerDelegate { var parent: DocumentPicker init(_ parent: DocumentPicker) { self.parent = parent } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { print("Success!", urls) guard let url = urls.first else { return } parent.onPicked(url) } func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { print("Picker was cancelled") } } } Run the project on Mac Catalyst to confirm it working. Try it out on a real iPhone. For some reason, I can't attach a video, so I can only show a screenshot
1
0
183
3d
Listening Changes Out of swiftUI in Observation Framework
Hi, folks. I know that in the new observation, class property changes can be automatically notified to SwiftUI, which is very convenient. But in the new observation framework, how to monitor the property changes of different model classes? For example, class1 has an instance of class2, and I need to notify class1 to perform some actions and make some changes when some properties of class2 are changed. How to do it in observation? In the past, I could use combined methods to write the second part of the code for monitoring. However, using the combined framework in observation is a bit confusing. I know this method can be withObservationTracking(_:onChange:) but it needs to be registered continuously. If Observation is not possible, do I need to change my design structure? Thanks. // Observation @Observable class Sample1 { var count: Int = 0 var name = "Sample1" } @Observable class Sample2 { var count: Int = 0 var name = "Sample2" var sample1: Sample1? init (sample1 : Sample1) { self.sample1 = sample1 } func render() { withObservationTracking { print("Accessing Sample1.count: \(sample1?.count ?? 0)") } onChange: { [weak self] in print("Sample1.count changed! Re-rendering Sample2.") self?.handleSample1CountChange() } } private func handleSample1CountChange() { print("Handling count change in Sample2...") self.count = sample1?.count ?? 0 } } // ObservableObject class Sample1: ObservableObject { @Published var count: Int = 0 var name = "Sample1" } class Sample2: ObservableObject { @Published var count: Int = 0 var name = "Sample1" var sample1: Sample1? private var cancellables = Set<AnyCancellable>() init (sample1 : Sample1) { self.sample1 = sample1 setupSubscribers() } private func setupSubscribers() { sample1?.$count .receive(on: DispatchQueue.main) .sink { [weak self] count in guard let self = self else { return } // Update key theory data self.count = count self.doSomeThing() } .store(in: &cancellables) } private func doSomeThing() { print("Count changes, need do some thing") } }
1
0
81
20h
Does LazyVStack and LazyVGrid release views from memory inside a ScrollView?
I am using LazyVStack inside a ScrollView. I understand that lazy views are rendered only when they come into view. However, I haven’t heard much about memory deallocation. I observed that in iOS 18 and later, when scrolling up, the bottom-most views are deallocated from memory, whereas in iOS 17, they are not (Example 1). Additionally, I noticed a similar behavior when switching views using a switch. When switching views by pressing a button, the view was intermittently deinitialized. (Example 2). Example 1) struct ContentView: View { var body: some View { ScrollView { LazyVStack { ForEach(0..<40) { index in CellView(index: index) } } } .padding() } } struct CellView: View { let index: Int @StateObject var viewModel = CellViewModel() var body: some View { Rectangle() .fill(Color.accentColor) .frame(width: 300, height: 300) .overlay { Text("\(index)") } .onAppear { viewModel.index = index } } } class CellViewModel: ObservableObject { @Published var index = 0 init() { print("init") } deinit { print("\(index) deinit") } } #Preview { ContentView() } Example 2 struct ContentView: View { @State var index = 0 var body: some View { LazyVStack { Button(action: { if index > 5 { index = 0 } else { index += 1 } }) { Text("plus index") } MidCellView(index: index) } .padding() } } struct MidCellView: View { let index: Int var body: some View { switch index { case 1: CellView(index: 1) case 2: CellView(index: 2) case 3: CellView(index: 3) case 4: CellView(index: 4) default: CellView(index: 0) } } } struct CellView: View { let index: Int @StateObject var viewModel = CellViewModel() var body: some View { Rectangle() .fill(Color.accentColor) .frame(width: 300, height: 300) .overlay { Text("\(index)") } .onAppear { viewModel.index = index } } } class CellViewModel: ObservableObject { @Published var index = 0 init() { print("init") } deinit { print("\(index) deinit") } } -------------------- init init init init init 2 deinit 3 deinit 4 deinit init
1
0
90
20h
Button taps in scroll views are not cancelled on scroll inside sheets
When you touch down on a button in a scroll view, you can cancel the tap by scrolling. In SwiftUI, this works correctly when the scroll view is not inside a dismissible sheet. However, if the scroll view is inside a sheet that can be dismissed with a drag gesture, scrolling does not cancel the button touch, and after scrolling, the button tap is activated. This happens whether the modal is presented from SwiftUI using the sheet modifier, or wrapped in a UIHostingController and presented from UIKit. This is a huge usability issue for modals with scrollable content that have buttons inside of them. Video of behavior: https://youtube.com/shorts/w6eqsmTrYiU Easily reproducible with this code: import SwiftUI struct ContentView: View { @State private var isPresentingSheet = false var body: some View { ScrollView { LazyVStack { ForEach(0..<100, id: \.self) { index in Button { isPresentingSheet = true } label: { Text("Button \(index)") .padding(.horizontal) .padding(.vertical, 5) .frame(maxWidth: .infinity, alignment: .leading) } } } .padding() } .sheet(isPresented: $isPresentingSheet) { ContentView() } } }
0
0
41
3h
SwiftUI: Sheet presented from List row is not removed from screen when row is removed
I noticed if I show a sheet from a List row, then remove the row the sheet isn't removed from the screen like it is if using VStack or LazyVStack. I'd be interested to know the reason why the sheet isn't removed from the screen in the code below. It only occurs with List/Form. VStack/LazyVStack gives the expected result. I was wondering if it is an implementation issue, e.g. since List is backed by UICollectionView maybe the cells can't be the presenter of the sheet for some reason. Launch on iPhone 16 Pro Simulator iOS 18.2 Tap "Show Button" Tap "Show Sheet" What is expected: The sheet should disappear after 5 seconds. And I don't mean it should dismiss, I just mean removed from the screen. Similarly if the View that showed the sheet was re-added and its show @State was still true, then the sheet would be added back to the screen instantly without presentation animation. What actually happens: Sheet remains on screen despite the row that presented the sheet being removed. Xcode 16.2 iOS Simulator 18.2. struct ContentView: View { @State var showButton = false var body: some View { Button("\(showButton ? "Hide" : "Show" ) Button") { showButton = true Task { try? await Task.sleep(for: .seconds(5)) self.showButton = false } } //LazyVStack { // does not have this problem List { if showButton { SheetButton() } } } } struct SheetButton: View { @State var sheet = false @State var counter = 0 var body: some View { Text(counter, format: .number) Button("\(sheet ? "Hide" : "Show") Sheet") { counter += 1 sheet.toggle() } .sheet(isPresented: $sheet) { Text("Wait... This should auto-hide in 5 secs. Does not with List but does with LazyVStack.") Button("Hide") { sheet = false } .presentationDetents([.fraction(0.3)]) } // .onDisappear { sheet = false } // workaround } } I can work around the problem with .onDisappear { sheet = false } but I would prefer the behaviour to be consistent across the container controls.
1
0
155
2d
SwiftUI: Major unannounced change in iOS18.4 beta1
Hi, I have noticed a major change to a SwiftUI API behavior in iOS18.4beta1 which breaks my app's functionality, and I've started hearing from users running the new beta that the app doesn't correctly work for them anymore. The problem is with views that contain a List with multiple-selection, and the contextMenu API applied with the ‘primaryAction’ callback that is triggered when the user taps on a row. Previously, if the user tapped on a row, this callback was triggered with the 'selectedItems' showing the tapped item. With iOS18.4beta, the same callback is triggered with ‘selectedItems’ being empty. I have the code to demonstrate the problem: struct ListSelectionTestView: View { @State private var items: [TimedItem] = [ TimedItem(number: 1, timestamp: "2024-11-20 10:00"), TimedItem(number: 2, timestamp: "2024-11-20 11:00"), TimedItem(number: 3, timestamp: "2024-11-20 12:00") ] @State var selectedItems = Set<TimedItem.ID>() var body: some View { NavigationStack { List(selection: $selectedItems) { ForEach(items) { item in Text("Item \(item.number) - \(item.timestamp)") } } .contextMenu(forSelectionType: TimedItem.ID.self, menu: {_ in Button(action: { print("button called - count = \(selectedItems.count)") }) { Label("Add Item", systemImage: "square.and.pencil") } }, primaryAction: {_ in print("primaryAction called - count = \(selectedItems.count)") }) } } } struct TimedItem: Identifiable { let id = UUID() let number: Int let timestamp: String } #Preview { ListSelectionTestView() } Running the same code on iOS18.2, and tapping on a row will print this to the console: primaryAction called - count = 1 Running the same code on iOS18.4 beta1, and tapping on a row will print this to the console: primaryAction called - count = 0 So users who were previously selecting an item from the row, and then seeing expected behavior with the selected item, will now suddenly tap on a row and see nothing. My app's functionality relies on the user selecting an item from a list to see another detailed view with the selected item's contents, and it doesn't work anymore. This is a major regression issue. Please confirm and let me know. I have filed a feedback: FB16593120
1
0
95
1d
Image & Text inside picker.
Hi, I am trying to use a flag image inside a picker like this: Picker("Title: ", selection: $selection){ ForEach(datas, id: \.self){ data in HStack{ Text(data.name) if condition { Image(systemName: "globe") }else { Image(img) } } .tag(data.name) .padding() } } All images are loading successfully but only system images are resized correctly. Images loaded from Assets are appearing in their default size. I have tried to size the images with frames, etc but with no luck. Any idea, help will be much appreciated. Thanks in advance!
2
0
80
8h
Simple console display test - preview not working as expected
Just learning Swift and SwiftUI, having fun in Xcode. I have the following custom view defined, but when I try to test it, the information doesn't get updated as I expect. When I use the button defined INSIDE the custom view, the update works as expected. When I use the button defined in the Preview body, it doesn't. The "lines" variable of the custom view appears not to be updated in that case. I know I'm missing something fundamental here about either view state binding or the preview environment, but I'm stumped. Any ideas? import SwiftUI struct ConsoleView: View { var maxLines : Int = 26 private enum someIDs { case textID} @State private var numLines : Int = 0 @State var lines = "a\nb\nc\n" var body: some View { VStack(alignment: .leading, spacing:0 ) { ScrollViewReader { proxy in ScrollView { Button("Scroll to Bottom") { withAnimation { proxy.scrollTo(someIDs.textID, anchor: .bottom) } } Text(lines) .id(someIDs.textID) .multilineTextAlignment(.leading) .frame(maxWidth: .infinity, alignment: .bottomLeading) .padding() .onChange ( of: lines) { withAnimation { proxy.scrollTo( someIDs.textID, anchor: .bottom) } } } Button("Add more") { writeln("More") //writeln(response) } } } } private func clipIfNeeded () { if (numLines>=maxLines) { if let i = lines.firstIndex(of: "\n") { lines = String(lines.suffix( from: lines.index(after:i))) } } } func writeln ( _ newText : String) { print("adding '\(newText)' to lines") //clipIfNeeded() write( newText ) write("\n") numLines += 1 print(lines) } func write ( _ newText : String) { lines += newText } } #Preview { VStack() { var myConsole = ConsoleView(lines: "x\ny\nz\n") myConsole Button("Add stuff") { myConsole.writeln("Stuff") } } }
2
0
146
2d
SwiftData crash when using a @Query on macOS 15.3.x
We use @Query macro in our App. After we got macOS 15.3 update, our App crashes at @Query line. SwiftData/Schema.swift:305: Fatal error: KeyPath \Item.<computed 0x0000000100599e54 (Vec3D)>.x points to a field (<computed 0x0000000100599e54 (Vec3D)>) that is unknown to Item and cannot be used. This problem occurs only when the build configuration is "Release", and only when I use @Query macro with sort: parameter. The App still works fine on macOS 14.7.3. This issue seems similar to what has already been reported in the forum. It looks like a regression on iOS 18.3. https://developer.apple.com/forums/thread/773308 Item.swift import Foundation import SwiftData public struct Vec3D { let x,y,z: Int } extension Vec3D: Codable { } @Model final class Item { var timestamp: Date var vec: Vec3D init(timestamp: Date) { self.timestamp = timestamp self.vec = Vec3D(x: 0, y: 0, z: 0) } } ContentView.Swift import SwiftUI import SwiftData struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query(sort: \Item.vec.x) // Crash private var items: [Item] var body: some View { NavigationSplitView { List { ForEach(items) { item in NavigationLink { Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))") } label: { Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) } } .onDelete(perform: deleteItems) } .navigationSplitViewColumnWidth(min: 180, ideal: 200) .toolbar { ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } detail: { Text("Select an item") } } private func addItem() { withAnimation { let newItem = Item(timestamp: Date()) modelContext.insert(newItem) } } private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(items[index]) } } } }
1
0
128
4d
Searchable list with binding causes indexOutOfRange crash on iOS 18 physical device
Hi folks, Unsure if I've implemented some sort of anti-pattern here, but any help or feedback would be great. I've created a minimal reproducible sample below that lets you filter a list of people and mark individuals as a favourite. When invoking the search function on a physical device running iOS 18.3.1, it crashes with Swift/ContiguousArrayBuffer.swift:675: Fatal error: Index out of range. It runs fine on iOS 17 (physical device) and also on the various simulators I've tried (iOS 18.0, iOS 18.2, iOS 18.3.1). If I remove the toggle binding, the crash doesn't occur (but I also can't update the toggles in the view model). I'm expecting to be able to filter the list without a crash occurring and retain the ability to have the toggle switches update the view model. Sample code is below. Thanks for your time 🙏! import SwiftUI struct Person { let name: String var isFavorite = false } @MainActor class ViewModel: ObservableObject { private let originalPeople: [Person] = [ .init(name: "Holly"), .init(name: "Josh"), .init(name: "Rhonda"), .init(name: "Ted") ] @Published var filteredPeople: [Person] = [] @Published var searchText: String = "" { didSet { if searchText.isEmpty { filteredPeople = originalPeople } else { filteredPeople = originalPeople.filter { $0.name.lowercased().contains(searchText.lowercased()) } } } } init() { self.filteredPeople = originalPeople } } struct ContentView: View { @ObservedObject var viewModel = ViewModel() var body: some View { NavigationStack { List { ForEach($viewModel.filteredPeople, id: \.name) { person in VStack(alignment: .leading) { Text(person.wrappedValue.name) Toggle("Favorite", isOn: person.isFavorite) } } } .navigationTitle("Contacts") } .searchable(text: $viewModel.searchText) } } #Preview { ContentView() }```
2
0
80
1d
Swift Charts: How to prevent scroll position jump when loading more data dynamically
I'm implementing infinite scrolling with Swift Charts where additional historical data loads when scrolling near the beginning of the dataset. However, when new data is loaded, the chart's scroll position jumps unexpectedly. Current behavior: Initially loads 10 data points, displaying the latest 5 When scrolling backwards with only 3 points remaining off-screen, triggers loading of 10 more historical points After loading, the scroll position jumps to the 3rd position of the new dataset instead of maintaining the current view Expected behavior: Scroll position should remain stable when new data is loaded User's current view should not change during data loading Here's my implementation logic using some mock data: import SwiftUI import Charts struct DataPoint: Identifiable { let id = UUID() let date: Date let value: Double } class ChartViewModel: ObservableObject { @Published var dataPoints: [DataPoint] = [] private var isLoading = false init() { loadMoreData() } func loadMoreData() { guard !isLoading else { return } isLoading = true let newData = self.generateDataPoints( endDate: self.dataPoints.first?.date ?? Date(), count: 10 ) self.dataPoints.insert(contentsOf: newData, at: 0) self.isLoading = false print("\(dataPoints.count) data points.") } private func generateDataPoints(endDate: Date, count: Int) -> [DataPoint] { var points: [DataPoint] = [] let calendar = Calendar.current for i in 0..<count { let date = calendar.date( byAdding: .day, value: -i, to: endDate ) ?? endDate let value = Double.random(in: 0...100) points.append(DataPoint(date: date, value: value)) } return points.sorted { $0.date < $1.date } } } struct ScrollableChart: View { @StateObject private var viewModel = ChartViewModel() @State private var scrollPosition: Date @State private var scrollDebounceTask: Task<Void, Never>? init() { self.scrollPosition = .now.addingTimeInterval(-4*24*3600) } var body: some View { Chart(viewModel.dataPoints) { point in BarMark( x: .value("Time", point.date, unit: .day), y: .value("Value", point.value) ) } .chartScrollableAxes(.horizontal) .chartXVisibleDomain(length: 5 * 24 * 3600) .chartScrollPosition(x: $scrollPosition) .chartXScale(domain: .automatic(includesZero: false)) .frame(height: 300) .onChange(of: scrollPosition) { oldPosition, newPosition in scrollDebounceTask?.cancel() scrollDebounceTask = Task { try? await Task.sleep(for: .milliseconds(300)) if !Task.isCancelled { checkAndLoadMoreData(currentPosition: newPosition) } } } } private func checkAndLoadMoreData(currentPosition: Date?) { guard let currentPosition, let earliestDataPoint = viewModel.dataPoints.first?.date else { return } let timeInterval = currentPosition.timeIntervalSince(earliestDataPoint) if timeInterval <= 3 * 24 * 3600 { viewModel.loadMoreData() } } } I attempted to compensate for this jump by adding: scrollPosition = scrollPosition.addingTimeInterval(10 * 24 * 3600) after viewModel.loadMoreData(). However, this caused the chart to jump in the opposite direction by 10 days, rather than maintaining the current position. What's the problem with my code and how to fix it?
0
0
88
1d
SwiftUI > missed . on frame modifier
Recently I've made 1 character mistake in my code and have hard time during searching what was the problem. Basically I forgot to set dot near one of the frame modifiers and compiler did not warn me, but during app running I got 100% CPU and rocket increase of RAM (on real app). Feels like recursion, but no any hint in call stack inside Xcode on crash stop. struct BadView: View { var body: some View { Color.red frame(height: 36) } } I would like to see at least warning for such cases. Problem may look simple on this small example, but if you added 1k+ lines after last compilation - searching this type of errors could be problematic when you have no idea what to search.
2
0
200
Oct ’24
Closure with typed throws stored as a View property crashes on iOS 17
I've encountered an issue where storing a throws(PermissionError) closure as a property inside a SwiftUI View causes a runtime crash on iOS 17, while it works correctly on iOS 18. Here’s an example of the affected code: enum PermissionError: Error { case denied } struct PermissionCheckedView<AllowedContent: View, DeniedContent: View>: View { var protectedView: () throws(PermissionError) -> AllowedContent var deniedView: (PermissionError) -> DeniedContent init( @ViewBuilder protectedView: @escaping () throws(PermissionError) -> AllowedContent, @ViewBuilder deniedView: @escaping (PermissionError) -> DeniedContent ) { self.protectedView = protectedView self.deniedView = deniedView } public var body: some View { switch Result(catching: protectedView) { case .success(let content): content case .failure(let error): deniedView(error) } } } @main struct TestApp: App { var body: some Scene { WindowGroup { PermissionCheckedView { } deniedView: { _ in } } } } Specifically this is the stack trace (sorry for the picture I didn't know how to get the txt): If I use var protectedView: () throws -> AllowedContent without typed throws it works.
2
0
169
6d
SwiftUI Sheet race condition
Hi! While working on my Swift Student Challenge submission it seems that I found a race condition (TOCTOU) bug in SwiftUI when using sheets, and I'm not sure if this is expected behaviour or not. Here's an example code: import SwiftUI struct ContentView: View { @State var myVar: Int? @State private var presentSheet: Bool = false var body: some View { VStack { // Uncommenting the following Text() view will "fix" the bug (kind of, see a better workaround below). // Text("The value is \(myVar == nil ? "nil" : "not nil")") Button { myVar = nil } label: { Text("Set value to nil.") } Button { myVar = 1 presentSheet.toggle() } label: { Text("Set value to 1 and open sheet.") } } .sheet(isPresented: $presentSheet, content: { if myVar == nil { Text("The value is nil") .onAppear { print(myVar) // prints Optional(1) } } else { Text("The value is not nil") } }) } } When opening the app and pressing the open sheet button, the sheet shows "The value is nil", even though the button sets myVar to 1 before the presentSheet Bool is toggled. Thankfully, as a workaround to this bug, I found out you can change the sheet's view to this: .sheet(isPresented: $presentSheet, content: { if myVar == nil { Text("The value is nil") .onAppear { if myVar != nil { print("Resetting View (TOCTOU found)") let mySwap = myVar myVar = nil myVar = mySwap } } } else { Text("The value is not nil") } }) This triggers a view refresh by setting the variable to nil and then to its non-nil value again if the TOCTOU is found. Do you think this is expected behaivor? Should I report a bug for this? This bug also affects .fullScreenCover() and .popover().
5
0
1.4k
Feb ’24
Slider .rotationEffect broken in MacOS 14.5
In a SwiftUI app for MacOS, vertical sliders that I'd created using a rotationEffect of 90° disappeared when I upgraded to Sonoma 14.5 (23F79). With rotations less than 90°, the slider is still visible, but its button is enlarged, growing in size as the rotation angle approaches 90°. Note that the sliders still work, even when rotated by 90° and invisible! The screenshot and code below demonstrates the problem, which did not exist in MacOS 14.2.1 struct ContentView: View { @State var speed = CGFloat(1) var body: some View { HStack { let angle: [Double] = [0, 45, 80, 85, 90] ZStack { ForEach(0...4, id: \.self) { i in ZStack () { Rectangle() Slider(value: $speed, in: 0...10 ) } .frame(width: 100, height: 10) .rotationEffect(.degrees(angle[i])) .offset(x: CGFloat(i * 100) - 180) } } } .padding() .frame(width: 600, height: 200) } } #Preview { ContentView() }
6
1
613
Jun ’24
SwiftUI.Entry macro only creating computed default values instead of stored?
https://gist.github.com/vanvoorden/37ff2b2f9a2a0d0657a3cc5624cc9139 Hi! I'm experimenting with the Entry macro in a SwiftUI app. I'm a little confused about how to stored a defaultValue to prevent extra work from creating this more than once. A "legacy" approach to defining an Environment variable looks something like this: struct StoredValue { var value: String { "Hello, world!" } init() { print("StoredValue.init()") } } extension EnvironmentValues { var storedValue: StoredValue { get { self[StoredValueKey.self] } set { self[StoredValueKey.self] = newValue } } struct StoredValueKey: EnvironmentKey { static let defaultValue = StoredValue() } } The defaultValue is a static stored property. Here is a "modern" approach using the Entry macro: struct ComputedValue { var value: String { "Hello, world!" } init() { print("ComputedValue.init()") } } extension EnvironmentValues { @Entry var computedValue: ComputedValue = ComputedValue() } From the perspective of the product engineer, it looks like I am defining another stored defaultValue property… but this actually expands to a computed property: extension EnvironmentValues { var computedValue: ComputedValue { get { self[__Key_computedValue.self] } set { self[__Key_computedValue.self] = newValue } } private struct __Key_computedValue: SwiftUICore.EnvironmentKey { static var defaultValue: ComputedValue { get { ComputedValue() } } } } If I tried to use both of these Environment properties in a SwiftUI component, it looks like I can confirm the computedValue is computing its defaultValue several times: @main struct EnvironmentDemoApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @Environment(\.computedValue) var computedValue @Environment(\.storedValue) var storedValue var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() } } And then when I run the app: ComputedValue.init() StoredValue.init() ComputedValue.init() ComputedValue.init() ComputedValue.init() ComputedValue.init() ComputedValue.init() ComputedValue.init() ComputedValue.init() Is there any way to use the Entry macro in a way that we store the defaultValue instead of computing it on-demand every time?
1
1
240
Dec ’24
iOS App Crashes with SIGABRT and XCTest.framework Not Loaded (Xcode 16.2, SwiftUI 6)
Hello Apple Developer Community, I’m experiencing an issue with my iOS app, "WaterReminder," where it builds successfully in Xcode 16.2 but crashes immediately upon launch in the iPhone 16 Pro Simulator running iOS 18.3.1. The crash is accompanied by a "Thread 1: signal SIGABRT" error, and the Xcode console logs indicate a dyld error related to XCTest.framework/XCTest not being loaded. I’ve tried several troubleshooting steps, but the issue persists, and I’d appreciate any guidance or insights from the community. Here are the details: Environment: Xcode Version: 16.2 Simulator: iPhone 16 Pro, iOS 18.3.1 App: WaterReminder (written in SwiftUI 6) Build Configuration: Debug Issue Description: The app builds without errors, but when I run it in the iPhone 16 Pro Simulator, it shows a white screen and crashes with a SIGABRT signal. The Xcode debugger highlights the issue in the main function or app delegate, and the console logs show the following error: dyld[7358]: Library not loaded: @rpath/XCTest.framework/XCTest Referenced from: <549B4D71-6B6A-314B-86BE-95035926310E> /Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/WaterReminder.debug.dylib Reason: tried: '/Users/faytek/Library/Developer/Xcode/DerivedData/WaterReminder-cahqrulxghamvyclxaozotzrbsiz/Build/Products/Debug-iphonesimulator/XCTest.framework/XCTest' (no such file), '/Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/Frameworks/XCTest.framework/XCTest' (no such file), '/Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/XCTest.framework/XCTest' (no such file), '/Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/Frameworks/XCTest.framework/XCTest' (no such file), '/Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/XCTest.framework/XCTest' (no such file), '/Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/Frameworks/XCTest.framework/XCTest' (no such file), '/Library/Developer/CoreSimulator/Volumes/iOS_22D8075/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 18.3.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/XCTest.framework/XCTest' (no such file) What I’ve Tried: ◦ Verified that FBSnapshotTestCase is correctly added to the "Embed Frameworks" build phase. ◦ Confirmed that the Framework Search Paths in build settings point to the correct location. ◦ Ensured that all required frameworks are available in the dependencies folder. ◦ Cleaned the build folder (Shift + Option + Command + K) and rebuilt the project. ◦ Checked the target configuration to ensure XCTest.framework isn’t incorrectly linked to the main app target (it’s only in test targets). ◦ Updated Xcode and the iOS Simulator to the latest versions. ◦ Reset the simulator content and settings. Despite these steps, the app continues to crash with the same dyld error and SIGABRT signal. I suspect there might be an issue with how XCTest.framework is being referenced or loaded in the simulator, possibly related to using SwiftUI 6, but I’m unsure how to resolve it. Could anyone provide advice on why XCTest.framework is being referenced in my main app (since it’s not intentionally linked there) or suggest additional troubleshooting steps? I’d also appreciate any known issues or workarounds specific to Xcode 16.2, iOS 18.3.1, and SwiftUI 6. Thank you in advance for your help! Best regards, Faycel
0
0
194
2d
LazyHstack in SwiftUI not supporting varying height views
In SwiftUI I want to create a list with LazyVstack and each row item in the LazyVstack is a LazyHstack of horizontally scrollable list of images with some description with line limit of 3 and width of every item is fixed to 100 but height of every item is variable as per description text content. But in any of the rows if the first item has image description of 1 line and the remaining items in the same row has image description of 3 lines then the LazyHStack is truncating all the image descriptions in the same row to one line making all the items in that row of same height. Why LazyHStack is not supporting items of varying height ? Expected behaviour should be that height of every LazyHStack should automatically adjust as per item content height. But it seems SwiftUI is not supporting LazyHstack with items of varying height. Will SwiftUI ever support this feature?
0
0
146
3d
Combining NavigationSplitView and TabView in iOS 18
Hi folks, I've used a NavigationSplitView within one of the tabs of my app since iOS 16, but with the new styling in iOS 18 the toolbar region looks odd. In other tabs using e.g. simple stacks, the toolbar buttons are horizontally in line with the new tab picker, but with NavigationSplitView, the toolbar leaves a lot of empty space at the top (see below). Is there anything I can do to adjust this, or alternatively, continue to use the old style? Thanks!
5
0
1.4k
Jul ’24