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

Posts under SwiftUI tag

200 Posts

Post

Replies

Boosts

Views

Activity

Why is this causing my app to crash?
I'm developing an app for my watch and have a list of different classes (referred to as 'courses' to avoid confusion) that I take in school, eg: struct Course { let name: String let icon: String let room: String let colour: String let listName: String let listIcon: String init(name: String, icon: String, room: String? = nil, colour: String, listName: String? = nil, listIcon: String? = nil) { self.name = name self.icon = icon self.room = room ?? "None" self.colour = colour self.listName = listName ?? name self.listIcon = listIcon ?? icon+".circle.fill" } } // here's a few of my Course variables (there are lots more I've excluded) let MathsCourse = Course(name: "Maths", icon: "number", room: "FT5", colour: "Rose") let English6 = Course(name: "English", icon: "book.closed", room: "BT6", colour: "Lemon") let LunchPeriod = Course(name: "Lunch", icon: "fork.knife", room: "food", colour: "White") and I have designed a 'list view' of all the courses I have on whatever day it is. I used to define a different View for every course I defined but I merged the list data with the overall Course and replaced the Views with something that I should be able to call repeatedly and pass in a course to use, but unfortunately it's not working. (yes, I'm making a timetable app) This is the template for a 'list view' for a class: struct courseListView: View { var localcourse: Course var localtime: String var body: some View { HStack{ Image(systemName: localcourse.listIcon) .foregroundColor(Color(localcourse.colour)) .padding(.leading, 5) Text(localcourse.name) .bold() Spacer() Text(localtime) Text(roomOrBlank(course: localcourse)).bold().padding(.trailing, 5) } .padding(.bottom, 1) .background(currentCourse.name==localcourse.name ? Color(localcourse.colour).colorInvert(): nil) } } Then I should be able to programmatically work out what courses I have that day (I haven't scripted that bit yet), and compose a view containing all the courses: struct ListView: View { var body: some View { ScrollView { VStack(alignment: .leading) { courseListView(localcourse: MathsCourse, localtime: "10:00") // ^^^ note above line; I'll come back to this // the idea is I can repeat that for a bunch of courses: courseListView(localcourse: English6, localtime: "11:00") courseListView(localcourse: LunchPeriod, localtime: "12:00") } } } } Then be able to call all that in my @main: @main struct Timetaber_Watch_AppApp: App { var body: some Scene { WindowGroup { TabView{ HomeView() ListView() SettingsView() } .tabViewStyle(.carousel) .onAppear() { log() } } } } Unfortunately, each time I try to get a list view for a course, // if you need a reminder: courseListView(localcourse: MathsCourse, localtime: "10:00") ...even only calling it once causes my entire app to crash. Here's an excerpt from the crash report: Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x0000000180210194 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [14932] Triggered by Thread: 0 Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 libdispatch.dylib 0x180210194 _dispatch_once_wait.cold.1 + 28 1 libdispatch.dylib 0x1801db4f4 _dispatch_once_wait + 184 2 ??? 0x3400200d0 ??? 3 ??? 0x340020198 ??? 4 ... So... Anyone know what's happening?
3
0
275
Mar ’25
iOS ImageRenderer Unable to localize text correctly Bug
A simple view has misaligned localized content after being converted to an image using ImageRenderer. This is still problematic on real phone and TestFlight I'm not sure what the problem is, I'm assuming it's an ImageRenderer bug. I tried to use UIGraphicsImageRenderer, but the UIGraphicsImageRenderer captures the image in an inaccurate position, and it will be offset resulting in a white border. And I don't know why in some cases it encounters circular references that result in blank images. "(1) days" is also not converted to "1 day" properly.
4
1
978
Mar ’25
SwiftUI Gestures: Sequenced Long Press and Drag
In creating a sequenced gesture combining a LongPressGesture and a DragGesture, I found that the combined gesture exhibits two problems: The @GestureState does not properly update as the gesture progresses through its phases. Specifically, the updating(_:body:) closure (documented here) is only ever executed during the drag interaction. Long presses and drag-releases do not call the updating(_:body:) closure. Upon completing the long press gesture and activating the drag gesture, the drag gesture remains empty until the finger or cursor has moved. The expected behavior is for the drag gesture to begin even when its translation is of size .zero. This second problem – the nonexistence of a drag gesture once the long press has completed – prevents access to the location of the long-press-then-drag. Access to this location is critical for displaying to the user that the drag interaction has commenced. The below code is based on Apple's example presented here. I've highlighted the failure points in the code with // *. My questions are as follows: What is required to properly update the gesture state? Is it possible to have a viable drag gesture immediately upon fulfilling the long press gesture, even with a translation of .zero? Alternatively to the above question, is there a way to gain access to the location of the long press gesture? import SwiftUI import Charts enum DragState { case inactive case pressing case dragging(translation: CGSize) var isDragging: Bool { switch self { case .inactive, .pressing: return false case .dragging: return true } } } struct ChartGestureOverlay<Value: Comparable & Hashable>: View { @Binding var highlightedValue: Value? let chartProxy: ChartProxy let valueFromChartProxy: (CGFloat, ChartProxy) -> Value? let onDragChange: (DragState) -> Void @GestureState private var dragState = DragState.inactive var body: some View { Rectangle() .fill(Color.clear) .contentShape(Rectangle()) .onTapGesture { location in if let newValue = valueFromChartProxy(location.x, chartProxy) { highlightedValue = newValue } } .gesture(longPressAndDrag) } private var longPressAndDrag: some Gesture { let longPress = LongPressGesture(minimumDuration: 0.2) let drag = DragGesture(minimumDistance: .zero) .onChanged { value in if let newValue = valueFromChartProxy(value.location.x, chartProxy) { highlightedValue = newValue } } return longPress.sequenced(before: drag) .updating($dragState) { value, gestureState, _ in switch value { case .first(true): // * This is never called gestureState = .pressing case .second(true, let drag): // * Drag is often nil // * When drag is nil, we lack access to the location gestureState = .dragging(translation: drag?.translation ?? .zero) default: // * This is never called gestureState = .inactive } onDragChange(gestureState) } } } struct DataPoint: Identifiable { let id = UUID() let category: String let value: Double } struct ContentView: View { let dataPoints = [ DataPoint(category: "A", value: 5), DataPoint(category: "B", value: 3), DataPoint(category: "C", value: 8), DataPoint(category: "D", value: 2), DataPoint(category: "E", value: 7) ] @State private var highlightedCategory: String? = nil @State private var dragState = DragState.inactive var body: some View { VStack { Text("Bar Chart with Gesture Interaction") .font(.headline) .padding() Chart { ForEach(dataPoints) { dataPoint in BarMark( x: .value("Category", dataPoint.category), y: .value("Value", dataPoint.value) ) .foregroundStyle(highlightedCategory == dataPoint.category ? Color.red : Color.gray) .annotation(position: .top) { if highlightedCategory == dataPoint.category { Text("\(dataPoint.value, specifier: "%.1f")") .font(.caption) .foregroundColor(.primary) } } } } .frame(height: 300) .chartOverlay { chartProxy in ChartGestureOverlay<String>( highlightedValue: $highlightedCategory, chartProxy: chartProxy, valueFromChartProxy: { xPosition, chartProxy in if let category: String = chartProxy.value(atX: xPosition) { return category } return nil }, onDragChange: { newDragState in dragState = newDragState } ) } .onChange(of: highlightedCategory, { oldCategory, newCategory in }) } .padding() } } #Preview { ContentView() } Thank you!
7
1
1.5k
Mar ’25
Issue with TabView in Split Screen
Below is a basic test app to resemble an actual app I am working on to hopefully better describe an issue I am having with tab view. It seems only in split screen when I am triggering something onAppear that would cause another view to update, or another view updates on its own, the focus gets pulled to that newly updated view instead of staying on the view you are currently on. This seems to only happen with views that are listed in the more tab. In any other orientation other than 50/50 split this does not happen. Any help would be appreciated. struct ContentView: View { @State var selectedTab = 0 var body: some View { NavigationStack { NavigationLink(value: 0) { Text("ENTER") }.navigationDestination(for: Int.self) { num in TabsView(selectedTab: $selectedTab) } } } } struct TabsView: View { @Binding var selectedTab: Int @State var yikes: Int = 0 var body: some View { if #available(iOS 18.0, *) { TabView(selection: $selectedTab) { MyFlightsView(yikes: $yikes) .tabItem { Label("My Flights", systemImage: "airplane.circle") }.tag(0) FlightplanView() .tabItem { Label("Flight Plan", systemImage: "doc.plaintext") }.tag(1) PreFlightView() .tabItem { Label("Pre Flight", systemImage: "airplane.departure") }.tag(2) CruiseView(yikes: $yikes) .tabItem { Label("Cruise", systemImage: "airplane") }.tag(3) PostFlightView() .tabItem { Label("Post Flight", systemImage: "airplane.arrival") }.tag(4) MoreView() .tabItem { Label("More", systemImage: "ellipsis") }.tag(5) NotificationsView() .tabItem { Label("Notifications", systemImage: "bell") }.tag(6) }.tabViewStyle(.sidebarAdaptable) } } }
1
0
346
Feb ’25
How can I optimize SwiftUI CPU load on frequent updates
Dear Sirs, I'm writing an audio application that should show up to 128 horizontal peakmeters (width for each is about 150, height is 8) stacked inside a ScrollViewReader. For the actual value of the peakmeter I have a binding to a CGFloat value. The peakmeter works as expected and is refreshing correct. For testing I added a timer to my swift application that is firing every 0.05 secs, meaning I want to show 20 values per second. Inside the timer func I'm just creating random CGFloat values in range of 0...1 for the bound values. The peakmeters refresh and flicker as expected but I can see a CPU load of 40-50% in the activity monitor on my MacBook Air with Apple M2 even when compiled in release mode. I think this is quite high and I'd like to reduce this CPU load. Should this be possible? I.e. I thought about blocking the refresh until I've set all values? How could this be done and would it help? What else could I do? Thanks and best regards, JFreyberger
7
0
1k
Feb ’25
System issues encountered when developing VisionOS related programs using Unity
Using Unity to develop VisionOS program, pressing the right knob of VisionPro during use will exit the Unity space and destroy the model in the space. The model in the space has been disconnected from the SwiftUI interface. After clicking the right knob, return to the system main interface, and then click the right knob again to return to the inside of the program. However, Unity space cannot be restored, and calling the discisWindow method on the SwiftUI interface has no effect, so the interface cannot be destroyed. Is there any solution??
1
0
326
Feb ’25
MacOS Scale to view
on iOS you can choose to scale to view to have the app resize the screen easily in the developer environment. Scale to view is however not easily done on MacOS using NS to solve on MacOS now. Is it possible for the Apple developer team to make this easier for the Developer, as I understand it is for iOS applications?
0
0
247
Feb ’25
What is a performant way to change view offset as user scrolls?
I added a background view to my SwiftUI List, and would like to move it up as user scrolls (similar to the effect of that of the Health app). I can't add it onto the background of a List row, because List unconditionally clips content to a row, and I would like the view to extend past a insetted row's bounds (scrollClipDisabled does not work on List). So I added the view as the background view of the entire List. Currently, I am achieving this by monitoring contentOffset using the new onScrollGeometryChange(for:of:action:) modifier, updating a state variable that controls the offset of the background view. The code looks something like this: struct ContentView: View { @State private var backgroundOffset: CGFloat = 0 var body: some View { List { ... } .background { backgroundView .offset(y: backgroundOffset) } .onScrollGeometryChange(for: ScrollGeometry.self) { geometry in geometry } action: { oldValue, newValue in let contentOffsetY = newValue.contentOffset.y let contentInsetY = newValue.contentInsets.top if contentOffsetY <= -contentInsetY { backgroundOffset = 0 } else { backgroundOffset = -(contentOffsetY + contentInsetY) } } } } However, this results in bad scrolling performance. I am guessing this is due to backgroundOffset being updated too frequently, and thus refreshing the views too often? If so, what is a more performant approach to achieve the desired effect? Thanks!
3
0
874
Feb ’25
Xcode 16: SwiftUI plain Button & UIImageView not working
It looks like Xcode 16 has changed this behaviour so I'm not sure if this is a bug or not. When a SwiftUI Button wraps a UIImageView and the button style is .plain the button doesn't work without setting isUserInteractionEnabled. struct ContentView: View { var body: some View { Button { print("Hello World!") } label: { UITestImage() } .buttonStyle(.plain) } } struct UITestImage: UIViewRepresentable { func makeUIView(context: Context) -> UIImageView { let view = UIImageView() // view.isUserInteractionEnabled = true // Fix view.image = UIImage(systemName: "plus") view.contentMode = .scaleAspectFit view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) view.setContentCompressionResistancePriority(.defaultLow, for: .vertical) view.layoutMargins = .zero return view } public func updateUIView(_ uiView: UIImageView, context: Context) {} } This feels unexpected, is this a bug?
2
1
934
Feb ’25
fullScreenCover not dismissed if binding changes rapidly.
I'm working on an app targeting iOS 15+ using SwiftUI. The app has several Views that load data from an API in their onAppear() method. While the loading operation is in progress, these views show a loading overlay via .fullScreenCover(). While most of the time this works as expected, I've discovered that if the API operation completes before the overlay's .onAppear() has fired, the overlay gets stuck on screen, i.e. does not dismiss. This bug occurs both in the simulator and on device. This is a simplified version of my implementation: struct MyDataView: View { @EnvironmentObject var store:Store var Content: some View { // ... } @ViewBuilder var body: some View { let showLoadingOverlay = Binding( get: { store.state.loading }, set: { _ in } ) Content .onAppear { store.dispatch(LoadData) } .fullScreenCover(isPresented: showLoadingOverlay) { LoadingOverlay() } } } Log messages tell me that my store is updating correctly, i.e. the booleans all operate as expected. Adding log output to the binding's getter always prints the correct value. Adding a breakpoint to the binding's getter makes the problem disappear. I've found that the chronology of events that lead to this bug is: MyDataView.onAppear() LoadData Binding: true Overlay starts animating in LoadData finishes Binding: false Overlay fires it's onAppear I.e. whenever loading finishes before the fullScreenCover's onAppear is fired, the overlay get's stuck on screen. As long as loading takes at least as long as it takes the overlay to appear, the bug does not occur. It appears to be a race condition between the .fullScreenCover appearing and the binding changing to false. I've found that the bug can be avoided if loading is triggered in the overlay's .onAppear(). However, I would like to avoid this workaround because the overlay is not supposed to carry out data loading tasks.
2
1
1.3k
Feb ’25
Are SwiftUI animations in UIKit & AppKit intentionally deprecated?
Is there some reason UIKit's and AppKit's animate(with:changes:completion:) methods are marked deprecated in iOS 18 when they were also first made available in iOS18? If they are indeed already deprecated, is there a replacement method we are supposed to use? This method allows the developer to use SwiftUI animations to animate UIKit and AppKit views.
1
0
342
Feb ’25
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() } } }
2
4
1.8k
Feb ’25
The SwiftUI project will compile normally in xcode15.4, but will not compile in xcode16.2. The log is as follows:
SwiftCompile normal arm64 Compiling\ Checkmark.swift,\ SimpleClockView.swift,\ Constants.swift,\ CountDayHomeView.swift,\ ................ logs.txt eekfnzfsodwhcebuwavalipzmswp/Build/Intermediates.noindex/FocusPomoTimer.build/Debug-iphonesimulator/FocusPomoTimer.build/DerivedSources/IntentDefinitionGenerated/AppRunningIntents/AppRunningIntentIntent.swift /Users/wangzhenghong/Library/Developer/Xcode/DerivedData/FocusPomoTimer-eekfnzfsodwhcebuwavalipzmswp/Build/Intermediates.noindex/FocusPomoTimer.build/Debug-iphonesimulator/FocusPomoTimer.build/DerivedSources/IntentDefinitionGenerated/AppRunningIntents/AppStopIntentIntent.swift /Users/wangzhenghong/Library/Developer/Xcode/DerivedData/FocusPomoTimer-eekfnzfsodwhcebuwavalipzmswp/Build/Intermediates.noindex/FocusPomoTimer.build/Debug-iphonesimulator/FocusPomoTimer.build/DerivedSources/GeneratedAssetSymbols.swift While evaluating request TypeCheckSourceFileRequest(source_file "/Users/wangzhenghong/MyApp/NewPomoProject/FocusPomoTimer/FocusPomoTimer/Views/TimerViews/SimpleClockView.swift") While evaluating request TypeCheckFunctionBodyRequest(FocusPomoTimer.(file).SimpleClockView._@/Users/wangzhenghong/MyApp/NewPomoProject/FocusPomoTimer/FocusPomoTimer/Views/TimerViews/SimpleClockView.swift:27:25) While evaluating request PreCheckResultBuilderRequest(FocusPomoTimer.(file).SimpleClockView._@/Users/wangzhenghong/MyApp/NewPomoProject/FocusPomoTimer/FocusPomoTimer/Views/TimerViews/SimpleClockView.swift:27:25) Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var LLVM_SYMBOLIZER_PATH to point to it): 0 swift-frontend 0x0000000107ab2a9c llvm::sys::PrintStackTrace(llvm::raw_ostream&amp;, int) + 56 1 swift-frontend 0x0000000107ab0cf0 llvm::sys::RunSignalHandlers() + 112 2 swift-frontend 0x0000000107ab3068 SignalHandler(int) + 292 3 libsystem_platform.dylib 0x000000019ee86de4 _sigtramp + 56 4 swift-frontend 0x0000000103d03758 swift::DiagnosticEngine::formatDiagnosticText(llvm::raw_ostream&amp;, llvm::StringRef, llvm::ArrayRefswift::DiagnosticArgument, swift::DiagnosticFormatOptions) + 432 5 swift-frontend 0x0000000103d042ac swift::DiagnosticEngine::formatDiagnosticText(llvm::raw_ostream&amp;, llvm::StringRef, llvm::ArrayRefswift::DiagnosticArgument, swift::DiagnosticFormatOptions) + 3332 6 swift-frontend 0x00000001028148d0 swift::AccumulatingFileDiagnosticConsumer::addDiagnostic(swift::SourceManager&amp;, swift::DiagnosticInfo const&amp;) + 944 7 swift-frontend 0x00000001028144e8 swift::AccumulatingFileDiagnosticConsumer::handleDiagnostic(swift::SourceManager&amp;, swift::DiagnosticInfo const&amp;) + 32 8 swift-frontend 0x0000000103d06960 swift::DiagnosticEngine::emitDiagnostic(swift::Diagnostic const&amp;) + 4276 9 swift-frontend 0x0000000102db4b10 swift::DiagnosticTransaction::~DiagnosticTransaction() + 184 10 swift-frontend 0x000000010350fbf0 (anonymous namespace)::PreCheckResultBuilderApplication::walkToExprPre(swift::Expr*) + 720 11 swift-frontend 0x0000000103bb9dac (anonymous namespace)::Traversal::visit(swift::Stmt*) + 2748 12 swift-frontend 0x00000001035093c8 swift::PreCheckResultBuilderRequest::evaluate(swift::Evaluator&amp;, swift::PreCheckResultBuilderDescriptor) const + 188 13 swift-frontend 0x00000001038bf294 swift::SimpleRequest&lt;swift::PreCheckResultBuilderRequest, swift::ResultBuilderBodyPreCheck (swift::PreCheckResultBuilderDescriptor), (swift::RequestFlags)2&gt;::evaluateRequest(swift::PreCheckResultBuilderRequest const&amp;, swift::Evaluator&amp;) + 36 14 swift-frontend 0x0000000103510568 swift::PreCheckResultBuilderRequest::OutputType swift::Evaluator::getResultCached&lt;swift::PreCheckResultBuilderRequest, swift::PreCheckResultBuilderRequest::OutputType swift::evaluateOrDefaultswift::PreCheckResultBuilderRequest(swift::Evaluator&amp;, swift::PreCheckResultBuilderRequest, swift::PreCheckResultBuilderRequest::OutputType)::'lambda'(), (void*)0&gt;(swift::PreCheckResultBuilderRequest const&amp;, swift::PreCheckResultBuilderRequest::OutputType swift::evaluateOrDefaultswift::PreCheckResultBuilderRequest(swift::Evaluator&amp;, swift::PreCheckResultBuilderRequest, swift::PreCheckResultBuilderRequest::OutputType)::'lambda'()) + 1256 15 swift-frontend 0x00000001035071f0 swift::TypeChecker::applyResultBuilderBodyTransform(swift::FuncDecl*, swift::Type) + 216 16 swift-frontend 0x00000001038c4d14 swift::TypeCheckFunctionBodyRequest::evaluate(swift::Evaluator&amp;, swift::AbstractFunctionDecl*) const + 484 17 swift-frontend 0x0000000103cd5e80 swift::TypeCheckFunctionBodyRequest::OutputType swift::Evaluator::getResultUncached&lt;swift::TypeCheckFunctionBodyRequest, swift::TypeCheckFunctionBodyRequest::OutputType swift::evaluateOrDefaultswift::TypeCheckFunctionBodyRequest(swift::Evaluator&amp;, swift::TypeCheckFunctionBodyRequest, swift::TypeCheckFunctionBodyRequest::OutputType)::'lambda'()&gt;(swift::TypeCheckFunctionBodyRequest const&amp;, swift::TypeCheckFunctionBodyRequest::OutputType swift::evaluateOrDefaultswift::TypeCheckFunctionBodyRequest(swift::Evaluator&amp;, swift::TypeCheckFunctionBodyRequest, swift::TypeCheckFunctionBodyRequest::OutputType)::'lambda'()) + 636 18 swift-frontend 0x0000000103c449f0 swift::AbstractFunctionDecl::getTypecheckedBody() const + 160 19 swift-frontend 0x00000001039130ec swift::TypeCheckSourceFileRequest::evaluate(swift::Evaluator&amp;, swift::SourceFile*) const + 868 20 swift-frontend 0x000000010391a680 swift::TypeCheckSourceFileRequest::OutputType swift::Evaluator::getResultUncached&lt;swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType swift::evaluateOrDefaultswift::TypeCheckSourceFileRequest(swift::Evaluator&amp;, swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType)::'lambda'()&gt;(swift::TypeCheckSourceFileRequest const&amp;, swift::TypeCheckSourceFileRequest::OutputType swift::evaluateOrDefaultswift::TypeCheckSourceFileRequest(swift::Evaluator&amp;, swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType)::'lambda'()) + 620 21 swift-frontend 0x0000000103912d6c swift::performTypeChecking(swift::SourceFile&amp;) + 328 22 swift-frontend 0x000000010282fe00 swift::CompilerInstance::performSema() + 260 23 swift-frontend 0x000000010245cdf0 performCompile(swift::CompilerInstance&amp;, int&amp;, swift::FrontendObserver*) + 1532 24 swift-frontend 0x000000010245bbb4 swift::performFrontend(llvm::ArrayRef&lt;char const*&gt;, char const*, void*, swift::FrontendObserver*) + 3572 25 swift-frontend 0x00000001023e2a5c swift::mainEntry(int, char const**) + 3680 26 dyld 0x000000019ead0274 start + 2840 Command SwiftCompile failed with a nonzero exit code
0
0
305
Feb ’25
SwiftUI infinite loop issue with @Environment(\.verticalSizeClass)
I see SwiftUI body being repeatedly called in an infinite loop in the presence of Environment variables like horizontalSizeClass or verticalSizeClass. This happens after device is rotated from portrait to landscape and then back to portrait mode. The deinit method of TestPlayerVM is repeatedly called. Minimally reproducible sample code is pasted below. The infinite loop is not seen if I remove size class environment references, OR, if I skip addPlayerObservers call in the TestPlayerVM initialiser. import AVKit import Combine struct InfiniteLoopView: View { @Environment(\.verticalSizeClass) var verticalSizeClass @Environment(\.horizontalSizeClass) var horizontalSizeClass @State private var openPlayer = false @State var playerURL: URL = URL(fileURLWithPath: Bundle.main.path(forResource: "Test_Video", ofType: ".mov")!) var body: some View { PlayerView(playerURL: playerURL) .ignoresSafeArea() } } struct PlayerView: View { @Environment(\.dismiss) var dismiss var playerURL:URL @State var playerVM = TestPlayerVM() var body: some View { VideoPlayer(player: playerVM.player) .ignoresSafeArea() .background { Color.black } .task { let playerItem = AVPlayerItem(url: playerURL) playerVM.playerItem = playerItem } } } @Observable class TestPlayerVM { private(set) public var player: AVPlayer = AVPlayer() var playerItem:AVPlayerItem? { didSet { player.replaceCurrentItem(with: playerItem) } } private var cancellable = Set<AnyCancellable>() init() { addPlayerObservers() } deinit { print("Deinit Video player manager") removeAllObservers() } private func removeAllObservers() { cancellable.removeAll() } private func addPlayerObservers() { player.publisher(for: \.timeControlStatus, options: [.initial, .new]) .receive(on: DispatchQueue.main) .sink { timeControlStatus in print("Player time control status \(timeControlStatus)") } .store(in: &cancellable) } }
2
0
396
Feb ’25
multidatepicker and saving multiple dates via swiftdata
Any help will be greatly appreciated. Trying to build a calendar/planner app for public school teachers. Classes are held on multiple dates so there is a need for swiftdata to save multiple dates. There are lots of tutorials demonstrating a multidatepicker but none of the tutorials or videos save the dates, via swiftdata. My goal is to save multiple dates. Step 1 is to initialize mockdata; this is done a class called ToDo. var dates:Set = [] Step 2 is the view containing a multidatepicker and other essential code Step 3 is to save multiple dates using swiftdata. Lots of tutorials, code snippets and help using a single date. But after almost 2 weeks of researching youtube tutorials, and google searches, I have not found an answer on how to save multiple dates via swiftdata. Also, I don't know how how to initialize the array of for the mockdata. Here are some code snippets used but the initialization of the array of DateComponenets doesnt work. And saving multiple dates doesn't work either @MainActor @Model class ToDo { var dates:Set<DateComponents> = [] init(dates: Set<DateComponents> = []) { self.dates = dates } } //view struct DetailView: View { @State var dates: Set<DateComponents> = [] @Environment(\.modelContext) var modelContext @State var toDo: ToDo @State private var dates: Set<DateComponents> = [] MultiDatePicker("Dates", selection: $dates) .frame(height: 100) .onAppear() { dates = toDo.dates } Button("Save") { //move data from local variables to ToDo object toDo.dates = dates //save data modelContext.insert(toDo) } } } #Preview { DetailView(toDo: ToDo()) .modelContainer(for: ToDo.self, inMemory: true) }
2
0
575
Feb ’25
iOS 18 SwiftUI navigation bar problem
Okay I know, fill a bug... but here is a super simple app that will demostrate that the navigation bar chnages from Dark scheme to light scheme when you tap back after it goes to the second view. import SwiftUI struct ContentView: View { var body: some View { NavigationStack { NavigationLink { Text("Tap back and notice the navigation title changes to black text instead of white") .toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(Color.orange, for: .navigationBar) .toolbarColorScheme(.dark, for: .navigationBar) } label: { VStack { Text("First page is the sweetest") } .padding() } .navigationTitle("First Page") .toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(Color.orange, for: .navigationBar) .toolbarColorScheme(.dark, for: .navigationBar) } } } #Preview { ContentView() }
6
9
4.6k
Feb ’25
Does `requestGeometryUpdate()` Override Orientation Lock by Design?
Hi everyone, I've been testing the requestGeometryUpdate() API in iOS, and I noticed something unexpected: it allows orientation changes even when the device’s orientation lock is enabled. Test Setup: Use requestGeometryUpdate() in a SwiftUI sample app to toggle between portrait and landscape (code below). Manually enable orientation lock in Control Center. Press a button to request an orientation change in sample app. Result: The orientation changes even when orientation lock is ON, which seems to override the expected system behavior. Questions: Is this intended behavior? Is there official documentation confirming whether this is expected? I haven’t found anything in Apple’s Human Interface Guidelines (HIG) or UIKit documentation that explicitly states this. Since this behavior affects a system-wide user setting, could using requestGeometryUpdate() in this way lead to App Store rejection? Since Apple has historically enforced respecting user settings, I want to clarify whether this approach is compliant. Would love any official guidance or insights from Apple engineers. Thanks! struct ContentView: View { @State private var isLandscape = false // Track current orientation state var body: some View { VStack { Text("Orientation Test") .font(.title) .padding() Button(action: toggleOrientation) { Text(isLandscape ? "Switch to Portrait" : "Switch to Landscape") .bold() .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(10) } } } private func toggleOrientation() { guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { print("No valid window scene found") return } // Toggle between portrait and landscape let newOrientation: UIInterfaceOrientationMask = isLandscape ? .portrait : .landscapeRight let geometryPreferences = UIWindowScene.GeometryPreferences.iOS(interfaceOrientations: newOrientation) scene.requestGeometryUpdate(geometryPreferences) { error in print("Failed to change orientation: \(error.localizedDescription)") } self.isLandscape.toggle() } }
1
0
346
Feb ’25
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
3
0
413
Feb ’25
UIViewControllerRepresentable inside a UIScrollView (List, ScrollView and etc) not working
Hi, I have a UIViewController that contains a UITextField I am presenting that view controller inside SwiftUI using a UIViewControllerRepresentable and I am able to interact with the text field fine and the view controller lifecycle executes normally if the representable is not presented on any SwiftUI container that internally uses a scroll view on the other hand if I put the representable view inside a SwiftUI view that has a scroll view internally (when the UIKit hierarchy is generated) the text field does not respond to interaction anymore and the only view controller lifecycle method invoked is the viewDidLoad from my view controller the other methods are not executed. Anyone knows if this is a bug on SwiftUI or if there is any additional setup necessary for UIViewControllerRepresentables? Thanks in advance.
4
2
1.5k
Feb ’25