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

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

SwiftUI Document-based apps crash in iOS 18
I am trying to integrate the new iOS 18 document launching experience with my app, but opening or saving files fails with the RC version of Xcode 16. The error I receive is "Publishing changes from background threads is not allowed." I downloaded Apple's new sample code ("Writing app"), and it fails with the same error. Is there an easy fix for this?
3
0
252
3w
Swift Charts - weak scrolling performance
Hello there! I wanted to give a native scrolling mechanism for the Swift Charts Graph a try and experiment a bit if the scenario that we try to achieve might be possible, but it seems that the Swift Charts scrolling performance is very poor. The graph was created as follows: X-axis is created based on a date range, Y-axis is created based on an integer values between moreless 0-320 value. the graph is scrollable horizontally only (x-axis), The time range (x-axis) for the scrolling content was set to one year from now date (so the user can scroll one year into the past as a minimum visible date (.chartXScale). The X-axis shows 3 hours of data per screen width (.chartXVisibleDomain). The data points for the graph are generated once when screen is about to appear so that the Charts engine can use it (no lazy loading implemented yet). The line data points (LineMark views) consist of 2880 data points distributed every 5 minutes which simulates - two days of continuous data stream that we want to present. The rest of the graph displays no data at all. The performance result: The graph on the initial loading phase is frozen for about 10-15 seconds until the data appears on the graph. Scrolling is very laggy - the CPU usage is 100% and is unacceptable for the end users. If we show no data at all on the graph (so no LineMark views are created at all) - the result is similar - the empty graph scrolling is also very laggy. Below I am sharing a test code: @main struct ChartsTestApp: App { var body: some Scene { WindowGroup { ContentView() Spacer() } } } struct LineDataPoint: Identifiable, Equatable { var id: Int let date: Date let value: Int } actor TestData { func generate(startDate: Date) async -> [LineDataPoint] { var values: [LineDataPoint] = [] for i in 0..<(1440 * 2) { values.append( LineDataPoint( id: i, date: startDate.addingTimeInterval( TimeInterval(60 * 5 * i) // Every 5 minutes ), value: Int.random(in: 1...100) ) ) } return values } } struct ContentView: View { var startDate: Date { return endDate.addingTimeInterval(-3600*24*30*12) // one year into the past from now } let endDate = Date() @State var dataPoints: [LineDataPoint] = [] var body: some View { Chart { ForEach(dataPoints) { item in LineMark( x: .value("Date", item.date), y: .value("Value", item.value), series: .value("Series", "Test") ) } } .frame(height: 200) .chartScrollableAxes(.horizontal) .chartYAxis(.hidden) .chartXScale(domain: startDate...endDate) // one year possibility to scroll back .chartXVisibleDomain(length: 3600 * 3) // 3 hours visible on screen .onAppear { Task { dataPoints = await TestData().generate(startDate: startDate) } } } } I would be grateful for any insights or suggestions on how to improve it or if it's planned to be improved in the future. Currently, I use UIKit CollectionView where we split the graph into smaller chunks of the graph and we present the SwiftUI Chart content in the cells, so we use the scrolling offered there. I wonder if it's possible to use native SwiftUI for such a scenario so that later on we could also implement some kind of lazy loading of the data as the user scrolls into the past.
0
0
152
2w
App freezes when built with Xcode 16 on iOS 18, but not on iOS 17 or lower, or with Xcode 15 on iOS 18
I'm experiencing an issue where my app freezes when built with Xcode 16 on iOS 18. Additional Information: The issue does not occur when building the app with Xcode 16 on iOS 17 or lower. The issue does not occur when building the app with Xcode 15 on iOS 18. The CPU usage spikes to 100% when the app freezes. The app specifically freezes after the code runs into .sink(receiveValue:). Here is the relevant code snippet: @Published var selectedCardData: CardData? @Published var selectedRootTab: RootViewTab = .statement override func load() { state = .loading $selectedCardData.ignoreNil() .removeDuplicates() .map { [unowned self] cardData in $selectedRootTab.filter { $0 == .statement } .first() .map { _ in cardData } } .switchToLatest() .sink(receiveValue: { value in print(value) // value not nil print("Execution reaches this point and the app freezes (CPU 100%).") }) .store(in: &cancellables) } Are there any known changes in iOS 18 or Xcode 16 that might affect this code?
2
2
254
2w
WidgetBundle with ControlWidget does not work on iOS 17
I'm trying to add a ControlWidget to my WidgetBundle like this: struct MyWidgets: WidgetBundle { var body: some Widget { if #available(iOSApplicationExtension 18.0, *) { LauncherControl() } MyLiveActivityWidget() HomeScreenWidget() LockScreenWidget() } This works exactly as expected on iOS 18. However on iOS 17 my app seems to have no widgets at all. The workaround described here (https://www.avanderlee.com/swiftui/variable-widgetbundle-configuration/) does not work either since WidgetBundleBuilder.buildBlock does not accept ControlWidget as an argument. What is the correct way to include a Control widget conditionally on iOS 18?
3
1
1.7k
Jul ’24
.alignmentGuide modifier causes consistent app crash when Swift 6 language mode is enabled
I've been experiencing random crashes in my app and today, I could finally narrow it down enough to start building an example project that consistently crashes. The error is this: "com.apple.SwiftUI.AsyncRenderer (19): EXC_BREAKPOINT (code=1, subcode=0x102f103f8)" It's a very strange bug because the SwiftUI view hierarchy has to be in a very specific shape to cause the crash, but if it is, then it crashes 100% of the time: It's a button inside a List and a simple "@State var number: Int?" that is being animated when the view appears. You can simply paste the following code into a project and run it (device, simulator or even in a preview): // Must be in Swift 6 Language Mode! // iOS 18 Beta 4 struct ContentView: View { @State var number: Int? var body: some View { List { // Must be in a List // It also crashes if button is here inside the List } .overlay { button } .task { // Has to be in a task modifier (or .onAppear + Task {}, so it has to be async) number = 0 } } // Has to be in a separate view property private var button: some View { Button {} label: { // Has to be this initializer and not Button(number == nil ? "" : "") {} if number == nil { // There has to be a conditional with "number" in here Color.clear } } .animation(.default, value: number) // Animation must be inside the List .alignmentGuide(VerticalAlignment.center) { dimension in dimension[VerticalAlignment.center] } } } The crash only happens under the following conditions, as far as I can tell: This only happens in the Swift 6 language mode (which I have enabled in the example project) It's related to an .alignmentGuide modifier attached to a button that also has an .animation modifier The button has to have a conditional view inside its label that checks for the same variable that is being animated The button must be inside a separate property that is put either inside a List or inside an overlay of a List The crash is then triggered when the animated value is asynchronously changed (in a .task modifier for example) The crash happens at least with Beta 3 and 4 of Xcode 16.0 I have also opened a feedback: FB14510236 but I thought I'd post it here as well because this crash was driving me crazy and maybe others might find it helpful for their debugging. Took me hours to find out what's been causing it 😅 Edit: Interestingly, when I run this project on an iOS 17 device, it does not crash, but rather print a runtime warning: "warning: data race detected: @MainActor function at AlignmentGuideCrash/ContentView.swift:27 was not called on the main thread" Line 27 is: .alignmentGuide(VerticalAlignment.center) { dimension in
4
1
353
Jul ’24
.matchedGeomtryEffect from View to Sheet.
I'm trying to accomplish something like this: https://x.com/mlaithv/status/1835041850236838265 But it seems like Apple uses a Private API to pull it off. Has anyone managed to create something similar? I know there is a package named Transmission that can do it but it seems hacky & I'm unfamiliar with UIKit. The source uses a "custom modal" but I'm not sure how.
0
0
152
3w
When using a SwiftData value for the customizationID of a TabView, that ID is not unique for a particular behavior.
In the customizationID modifier of the TabView, if I use an ID with a SwiftData value, it returns the following error when I open a new window on iPadOS: “Not unique” even when using a UUID. I can't do anything about it, so I'm posting it here. Any advice that could help me on the way to solving this problem would be appreciated. Thread 1: "Fatal: supplied item identifiers are not unique. Duplicate identifiers: {(\n "Tab.Custom.1C350509-C28A-4C41-85A0-3EA57779DB1B"\n)}" Below is a portion of the code that reproduces this phenomenon. I believe it is sufficient for your needs, but if you need more code, we can accommodate. struct ContentView: View { @Environment(\.modelContext) var modelContext @Query private var tags: [Tag] @AppStorage("Customization") private var customization: TabViewCustomization @State private var isAdding = false @State private var tagName = "" var body: some View { TabView { Tab("Home", systemImage: "house") { NavigationStack { Label("Home", systemImage: "house") .toolbar { ToolbarItem(placement: .primaryAction) { Button { isAdding.toggle() } label: { Label("Add Tag", systemImage: "plus") } } } } } .customizationID("Tab.Home") Tab("Workplace", systemImage: "building.2") { NavigationStack { Label("Workplace", systemImage: "building.2") .toolbar { ToolbarItem(placement: .primaryAction) { Button { isAdding.toggle() } label: { Label("Add Tag", systemImage: "plus") } } } } } .customizationID("Tab.Workplace") Tab("Apple Store", systemImage: "apple.logo") { NavigationStack { Label("Apple Store", systemImage: "apple.logo") .toolbar { ToolbarItem(placement: .primaryAction) { Button { isAdding.toggle() } label: { Label("Add Tag", systemImage: "plus") } } } } } .customizationID("Tab.AppleStore") TabSection { ForEach(tags) { tag in Tab(tag.name, systemImage: "tag") { NavigationStack { Label(tag.name, systemImage: "tag") .toolbar { ToolbarItem(placement: .primaryAction) { Button { isAdding.toggle() } label: { Label("Add Tag", systemImage: "plus") } } } } } .customizationID("Tab.Custom.\(tag.id.uuidString)") } } header: { Label("Custom", systemImage: "tag") } .customizationID("TabSection.AppleStore") .sectionActions { Button { isAdding.toggle() } label: { Label("Add Tag", systemImage: "plus") } } } .tabViewCustomization($customization) .tabViewStyle(.sidebarAdaptable) .alert("Create Tag", isPresented: $isAdding) { TextField("Tag Name", text: $tagName) Button("Cancel") { tagName = "" isAdding = false } Button("Done") { let tagList = tagName.components(separatedBy: .whitespaces) for tagItem in tagList { if tagItem != "" && tags.filter({return $0.name == tagItem}).isEmpty { let newTag = Tag(name: tagItem) modelContext.insert(newTag) } } try? modelContext.save() tagName = "" isAdding = false } } } } import SwiftData import Foundation @Model final class Tag: Identifiable { var id: UUID = UUID() var name: String = "" init(name: String) { self.id = UUID() self.name = name } } How to reproduce Implement the above code so that it works. Build the application on the actual iPad device using Xcode. Add tags (data) Open a new window and check the UI behavior. Correct Behavior The ID is not actually unique. Or, if it is unique, it should not freeze without generating an error. Actual Behavior The ID should be set to be unique, but it freezes with an error that it is not unique. Environment iPadOS 18 RC (22A3354) Xcode 16.0 (16A242)
0
0
184
3w
Text Max Character Number SwiftUI
Hi, Some times long text damage the design of views it might go to a second row and increase view height and damage the overall design, so how to solve this issue, is there a way to set a Max Characters number for Text and TextField views in SwiftUI ? and maybe show few dots as used in some designs ? Kind Regards
1
0
169
3w
Issue with Keyboard Avoidance for Sheet View in SwiftUI
I am currently working on a comments section modeled after TikTok's/Instagram's comment sections for a media app. The view is a sheet view that is presented as follows: .sheet(isPresented: $showChat) { TakesChatView(viewModel: viewModel) .presentationDetents([.medium, .large]) .presentationDragIndicator(.hidden) .overlay( VStack { RoundedRectangle(cornerRadius: 2) .fill(Color.gray) .frame(width: 40, height: 5) .padding(.top, 15) .opacity(0.8) Label("Chat", systemImage: "message.badge") .lineLimit(nil) .padding(.top, 5) .padding([.leading, .trailing], 16) Divider() .padding(.top, 5) .padding([.leading, .trailing], 16) Spacer() } .frame(maxWidth: .infinity, alignment: .top) ) }.ignoresSafeArea(.keyboard, edges: .bottom) However, some issues arise regarding keyboard avoidance. Currently, when the user taps on the TextField to type a comment, the keyboard shifts the entire view upwards as it pops up. Instead, I need it where I can still view the comments without the keyboard affecting their placement when it pop up. Below is the associated code for the comment view: struct TakesChatView: View { @ObservedObject var viewModel: TakeCommentViewModel @FocusState var focus: Bool @State private var selectedMedia: [PhotosPickerItem] = [] @State private var selectedImageData: [Data] = [] @State private var selectedGIFData: [Data] = [] @State private var selectedVideoData: [Data] = [] var textFieldNotEmpty: Bool { !viewModel.textToPost.isEmpty || !selectedImageData.isEmpty || !selectedGIFData.isEmpty || !selectedVideoData.isEmpty } var body: some View { GeometryReader { _ in ZStack { VStack { contentView commentTextField .padding(.top,5) } } } .ignoresSafeArea(.keyboard, edges: .bottom) .background(Color.containerBackground) .onChange(of: viewModel.focus) { focus in self.focus = focus } .onChange(of: selectedMedia) { _ in loadMedia() } } var contentView: some View { VStack { Spacer().frame(height: 105) ScrollViewReader { scroll in ScrollView(showsIndicators: true) { ForEach(viewModel.comments, id: \.self) { comment in TakeCommentView( comment: comment, viewModel: self.viewModel ) .padding(.horizontal, 10) .id(comment.documentID) } .onChange(of: viewModel.commentAdded) { id in scroll.scrollTo(id, anchor: .bottom) viewModel.commentAdded = nil } } .scrollDismissesKeyboard(.immediately) } } } } extension TakesChatView { var commentTextField: some View { VStack { mediaPreview HStack { TextField("Type your comment", text: $viewModel.textToPost, axis: .vertical) .keyboardType(.twitter) .padding([.leading, .vertical], 6) .focused($focus) PhotosPicker(selection: $selectedMedia, matching: .any(of: [.images, .videos]), photoLibrary: .shared()) { ComposeType.media.image .frame(width: 40, height: 40, alignment: .center) } .onAppear { selectedMedia.removeAll() selectedImageData.removeAll() selectedGIFData.removeAll() selectedVideoData.removeAll() } postButton } .border(.lightGray, width: 1, cornerRadius: 10) .padding([.bottom, .horizontal], 10) } } } I have tried using .ignoresSafeAres(), .safeAreaInset(), and custom keyboard observer functions but to no avail. How do I fix this issue?
0
0
180
3w
Struggling with Swift Gesture/Observation
I'm trying to create an equivalent to TabView, but with the difference that the 2nd View slides in over the top of the primary view. Maybe there's a more elegant way of coding this (suggestions appreciated), but I've almost succeeded using the dragGesture. When a user swipes right to left the observed variable showTab2 is set to true, and the 2nd tab glides in over the top of tab 1 and displays 🥳. The only problem is, that when a user happens to start the swipe over a button, the observed status (showTab2) does change as expected but the main view does not catch this change and does not display tab2. And that despite the showTab2 being an @Observable. Any clues what I've missed? Or how to capture that the start of a swipe gesture starts over the top of a button and should be ignored. According to the code in SwipeTabView this screenshot 👆 should never occur. Here's the code: @Observable class myclass { var showTab2 = false } struct SwipeTabView: View { @State var myClass = myclass() @State var dragAmount: CGSize = CGSize.zero var body: some View { VStack { ZStack { GeometryReader { geometryProxy in VStack { tab(tabID: 1, selectedTab: myClass.showTab2) .zIndex(/*@START_MENU_TOKEN@*/1.0/*@END_MENU_TOKEN@*/) .background(.black) .transition(.identity) .swipeable(stateOfViewAdded: $myClass.showTab2, dragAmount: $dragAmount, geometryProxy: geometryProxy, insertion: true) } if myClass.showTab2 || dragAmount.width != 0 { tab(tabID: 2, selectedTab: myClass.showTab2) .zIndex(2.0) .drawingGroup() .transition(.move(edge: .trailing)) .offset(x: dragAmount.width ) .swipeable(stateOfViewAdded: $myClass.showTab2, dragAmount: $dragAmount, geometryProxy: geometryProxy, insertion: false) } } } } } } extension View { func swipeable(stateOfViewAdded: Binding<Bool>, dragAmount: Binding<CGSize>, geometryProxy: GeometryProxy, insertion: Bool) -> some View { self.gesture( DragGesture() .onChanged { gesture in // inserting must be minus, but removing must be positive - hence the multiplication. if gesture.translation.width * (insertion ? 1 : -1 ) < 0 { if insertion { dragAmount.wrappedValue.width = geometryProxy.size.width + gesture.translation.width } else { dragAmount.wrappedValue.width = gesture.translation.width } } } .onEnded { gesture in if abs(gesture.translation.width) > 100.0 && gesture.translation.width * (insertion ? 1 : -1 ) < 0 { withAnimation(.easeOut.speed(Double(gesture.velocity.width))) { stateOfViewAdded.wrappedValue = insertion } } else { withAnimation(.easeOut.speed(Double(gesture.velocity.width))) { stateOfViewAdded.wrappedValue = !insertion } } withAnimation(.smooth) { dragAmount.wrappedValue = CGSize.zero } } ) } } struct tab: View { var tabID: Int var selectedTab: Bool var body: some View { ZStack { Color(tabID == 1 ? .yellow : .orange) VStack { Text("Tab \(tabID) ").foregroundColor(.black) Button(action: { print("Tab2 should display - \(selectedTab.description)") }, label: { ZStack { circle label } }) Text("Tab2 should display - \(selectedTab.description)") } } } var circle: some View { Circle() .frame(width: 100, height: 100) .foregroundColor(.red) } var label: some View { Text("\(tabID == 1 ? ">>" : "<<")").font(.title).foregroundColor(.black) } }
4
0
251
3w
Tab button's ax identifier is missing when using `.sidebarAdaptable` TabViewStyle
Hello, I found that if you apply the new .sidebarAdaptable tab view style, the accessibility identifiers of tab bar buttons are missing. import SwiftUI struct ContentView: View { var body: some View { TabView { Tab("Received", systemImage: "tray.and.arrow.down.fill") { Text("Received") } .accessibilityIdentifier("tab.received") // 👀 Tab("Sent", systemImage: "tray.and.arrow.up.fill") { Text("Sent") } .accessibilityIdentifier("tab.sent") // 👀 Tab("Account", systemImage: "person.crop.circle.fill") { Text("Account") } .accessibilityIdentifier("tab.account") // 👀 } .tabViewStyle(.sidebarAdaptable) // 👈 if remove this, ax identifiers are ok } } #Preview { ContentView() } The identifiers automatically appear after a few seconds. But this behaviour breaks a lot of the UI test cases.
2
0
159
3w
Scroll to Top gesture doesn't work when pressed in Status Bar.
I have created a paging app With SwiftUI TabView with TabViewStyle: PageTabViewStyle. In every page there is an UICollectionView holding a list of rows. Now I have used UIViewControllerRepresentable to show the view inside TabView. It works okay, but the Scroll to top gesture doesn't work here when pressed in the iPhones StatusBar. Is it a fault of TabView or I am missing Something? It may happen because of TabViews Scroll property. In UIKIT Views We needed to disable the scrollToTop property of scrollviews (Other then the desired one) is there any public API's for SwiftUI Views in replacement for setting scrollsToTop property?
3
0
174
3w
LongPressGesture does not work as expected in Xcode Version 16.0 (16A242) and iOS 18
When I copy and paste example code in apple developer documentation, LongPressGesture does not work as expected in Xcode Version 16.0 (16A242) and iOS 18. It seems updating(_:body:) method does not work when used with LongPressGesture. When I make a breakpoint in updating(_:body:) method and long press the blue circle on the screen of simulator(or device), it is expected to be caught in breakpoint or it is expected that color of circle turns from blue to red to green. However, it is not caught in breakpoint and never turns to red. Question of Stackoverflow is about same issue and I can not use onLongPressGesture method to implement required feature of my app. Development environment: Xcode Version 16.0 (16A242), macOS 14.5 Run-time configuration: iOS 18.0
6
8
369
3w
WKHaptic Issue when headphones are connected
Info watchOS: 11.0 (22R5348a) *Though has been present since watchOS 10. Issue: Other apps playing music cancel out WKHaptics from firing (low volume and no vibrations) Description When another app is playing music (ex: spotify) in the background while using my app, that uses WKHaptics. The WKHaptics vibrations are non existent as long as headphones are connected. When the headphones are disconnected the vibrations return. Test MVP test app >> https://github.com/mazefest/AppleCodeSupportTestApp
1
0
227
3w
SwiftUI bug using .sheet(item:) and button action not called
import SwiftUI extension Int: Identifiable { public var id: Int { return self } } struct ContentView: View { @State var shareSheet: Bool = false @State var selectedNo : Int? var body: some View { VStack { ForEach(0..<2, id: \.self, content: { rowNo in Text("world \(rowNo)") Button(action: { shareSheet.toggle() selectedNo = rowNo }) { Text("Go to world\(rowNo)") } }) } .padding() .sheet(item: $selectedNo) { row in // BUG: when replacing 'row' below with 'selectedNo' nil is passed. ShareView(message:"Hello \(row)" ) } } struct ShareView: View { let message: String var body: some View { Text(message) } } }
2
0
148
3w
SwiftUI `onOpenURL` lacks `referrerURL` and `annotation` present in NSUserActivity
Hello, I am working on an application that utilizes both AppDelegate and SceneDelegate. We are looking to convert the top level app to SwiftUI and start using the SwiftUI App lifecycle. When implementing, I see that deep links when the app is backgrounded will only route to the onOpenURL modifier. This means that information we relied on before like referrerURL and annotation present in the NSUserActivity object delivered to the app is no longer available. Is there any work around for this? It seems like missing functionality because there is no way to route the deep links through AppDelegate or SceneDelegate if you are using the SwiftUI App protocol.
4
1
404
May ’24
Variable for DestinationView
var body: some View { VStack { List { ForEach(starSigns) {ZodiacSign in NavigationLink(destination: ZodiacSign.DestinationView) { Text(ZodiacSign.Symbol) Text(ZodiacSign.name) } } } } } } I have this basic view which gets information from a list I created, but how do I get the destination view to work where an example of it would be AriesView(), I would like the destination to be there. Currently it comes up with an error of "Protocol 'View ' cannot conform to the protocol itself" Sorry for the complexity of this question, I was struggling to explain it. THANK YOU IN ADVANCE!!!
5
0
228
3w
PhotosPicker fail to load Collections tab on iOS 18
When using PhotosPicker in SwiftUI to let users pick a photo, it will fail to load after switching to the "Collections" tab on iOS 18. This issue doesn't occur on iOS 17. Additionally, using PHPickerViewController will still have the same issue. The code is pretty simple: struct ContentView: View { @State private var selection: PhotosPickerItem? = nil var body: some View { VStack { PhotosPicker("Pick photo", selection: $selection) } .padding() } } And I create a repo for this code: https://github.com/JuniperPhoton/PhotosPickerIssueiOS18 This issue has been reported via Feedback app, and the report ID is FB15069998. I tested in the Xcode 16 Beta 6 and iOS 18 Beta 8. However with the Xcode 16 RC and the iOS 18 RC, this issue still exists. Hoping to find out any workaround to resolve this issue. Thanks.
1
1
224
3w