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

SwiftUI Documentation

Posts under SwiftUI subtopic

Post

Replies

Boosts

Views

Activity

Very annoying warnings using XCode and SwiftUI
I recently changed my old ancient MacBookPro for a MBAir 15" M2., mainly to upgrade Xcode and Swift to SwiftUI. But using Xcode 15.1, trying to update the preview, or trying to run the code I get bombarded by these warnings: managedappdistributiond unexpectedly quit findmylocated unexpectedly quit aegirposter unexpectedly quit. The warnings are so frequent that it stops me programming. Mind, I'm not a professional programmer, rather a very driven amateur, but I don't think this this is what is meant by offering a great API. Can someone please help me get rid off all this irritating stuff.
17
11
2.9k
Dec ’23
SwiftUI creating MapCameraPosition from CLLocationManager initialiser/self error when trying to tie them? (see code)
Trying to use new Swift @Observable to monitor GPS position within SwiftUI content view. But how do I tie the latest locations to the SwiftUI Map's mapCameraPosition? Well ideally the answer could cover: How to fix this error - So get map tracking along with the User Position, but also How to include facility to turn on/off the map moving to track the user position (which I'll need to do next). So could be tracking, then disable, move map around and have a look at things, then click button to start syncing the mapcameraposition to the GPS location again Refer to error I'm embedded in the code below. import SwiftUI import MapKit @Observable final class NewLocationManager : NSObject, CLLocationManagerDelegate { var location: CLLocation? = nil private let locationManager = CLLocationManager() func startCurrentLocationUpdates() async throws { if locationManager.authorizationStatus == .notDetermined { locationManager.requestWhenInUseAuthorization() } for try await locationUpdate in CLLocationUpdate.liveUpdates() { guard let location = locationUpdate.location else { return } self.location = location } } } struct ContentView: View { var newlocationManager = NewLocationManager() @State private var cameraPosition: MapCameraPosition = .region(MKCoordinateRegion( center: newlocationManager.location?.coordinate ?? <#default value#>, span: MKCoordinateSpan(latitudeDelta: 0.25, longitudeDelta: 0.25) )) // GET ERROR: Cannot use instance member 'newlocationManager' within property initializer; property initializers run before 'self' is available var body: some View { ZStack { Map(position: $cameraPosition) Text("New location manager: \(newlocationManager.location?.description ?? "NIL" )") // works } .task { try? await newlocationManager.startCurrentLocationUpdates() } } } #Preview { ContentView() }
2
0
1.5k
Jan ’24
matchedGeometryEffect flickers in a TabView
I tried building the View from this section, but when there is a List on the second tab, the animation performed by the matchedGeometryEffect does not work as intended. This video shows how the transition works with Text("Second Tab") as the second tab. Everything looks fine. But when I replace the Text with a List, the transition flickers and does not look smooth anymore. List { Text("The Scarlet Letter") Text("Moby-Dick") Text("Little Women") Text("Adventures of ") } Here is the code for the app. import SwiftUI @main struct MyWatchApp: App { @Namespace var library @State var pageNumber = 0 private let bookIcon = "bookIcon" var body: some Scene { WindowGroup { NavigationStack { TabView(selection: $pageNumber) { VStack { Image(systemName: "books.vertical.fill") .imageScale(.large) .matchedGeometryEffect( id: bookIcon, in: library, properties: .frame, isSource: pageNumber == 0) Text("Books") } .tag(0) Text("Second Tab").tag(1) } .tabViewStyle(.verticalPage) .toolbar { ToolbarItem(placement: .topBarLeading) { Image(systemName: "books.vertical.fill") .matchedGeometryEffect( id: bookIcon, in: library, properties: .frame, isSource: pageNumber != 0) } } } } } }
1
2
934
Jan ’24
EnvironmentObject Causes SwiftUI App to Crash When Launched in the Background
I recently encountered a difficult-to-diagnose bug in an app that I'm working on, and I thought I would share it with the Apple Developer community. The app that I'm working on is an iOS app that uses Core Location's Visit Monitoring API, and it is essential that the app is able to process incoming visits while running in the background. However, after real-world testing, I discovered several crash reports which were difficult to understand, as SwiftUI symbols are not symbolicated on debug builds. Eventually I discovered that the app was crashing when calling an @EnvironmentObject property of the root ContentView from that view's body when the app was launched directly into the background from not running at all. After creating a small test app to isolate the problem, I discovered that any environment object declared in the App struct and referenced from the root ContentView causes the crash, with the exception message: "Fatal error: No ObservableObject of type ArbitraryEnvObject found. A View.environmentObject(_:) for ArbitraryEnvObject may be missing as an ancestor of this view." It seems that when a SwiftUI app is launched in the background, the ContentView's body is executed, but the environment is not initialized. I searched through as much documentation as I could, but could not find any information about how this should be handled, so I think it's a bug in SwiftUI. I have filed a Feedback Assistant bug report. The current workaround is to convert my ObservableObject into an object that conforms to the new @Observable protocol, add it to the scene as an Environment Value with the .environment(_:) modifier rather than the .environmentObject(_:) modifier, and declare the @Environment property on the view as optional. The object will still be missing when the app is launched in the background, but the optional property can be handled safely to prevent a crash. Attached to this post is a sample project that demonstrates the issue and the workaround. And finally, I'd like to hear from anyone who knows more about the expected behavior of background launches of SwiftUI apps, and whether or not there's something I should be doing completely differently. I'm not able to directly attach a zip archive to this post, so here's an iCloud link to the sample project: BackgroundEnvObjCrash.zip
6
2
4.1k
Jan ’24
SwiftUI view not updated after SwiftData change through CloudKit
A SwiftUI view is displaying a SwiftData model object that's being updated on another device, using CloudKit. The update arrives through CloudKit and the view is correctly updated. However, when the view is not displaying the model object directly, but in a nested view, this nested view is NOT updated. Why not? Is this a bug? Or is it just me, forgetting about some elementary detail? A workaround (that I definitely don't like!) is to put a dummy SwiftData query in the nested view. Even when the dummy query result is never used, the view now IS updated correctly. Why? The code below is mostly Xcode's standard template for a SwiftUI+SwiftData+CloudKit app, modified to use a String property i.s.o. a Date, and to be able to edit that name in a Textfield. The ContentView: struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var items: [Item] var body: some View { NavigationSplitView { List { ForEach(items) { item in @Bindable var item = item NavigationLink { VStack(alignment: .leading) { // item details in same view TextField(item.name, text: $item.name) .textFieldStyle(.roundedBorder) .padding() .background(.red.opacity(0.5)) // item details in nested view ItemDetailView(item: item) .padding() .background(.yellow.opacity(0.5)) Spacer() } } label: { Text(item.name) } } .onDelete(perform: deleteItems) } #if os(macOS) .navigationSplitViewColumnWidth(min: 180, ideal: 200) #endif .toolbar { #if os(iOS) ToolbarItem(placement: .navigationBarTrailing) { EditButton() } #endif ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } detail: { Text("Select an item") } } private func addItem() { withAnimation { let newItem = Item(name: "item") modelContext.insert(newItem) } } private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(items[index]) } } } } The nested ItemDetailView: struct ItemDetailView: View { @Bindable var item: Item // dummy query to force view updates triggered by CloudKit // @Query private var items: [Item] var body: some View { TextField(item.name, text: $item.name) .textFieldStyle(.roundedBorder) } } The result:
3
3
1.2k
Jan ’24
Toolbar buttons disappearing when showing a navigation split view as a sheet
When displaying a view using a navigation Split View as a sheet, the toolbar button will disappear if you leave the app and resume it. import SwiftUI struct Folder: Hashable, Identifiable { let id = UUID() let name: String } struct ContentView: View { @State private var showingSettings = false var body: some View { VStack { Button { showingSettings.toggle() } label: { Text("Settings") } } .sheet(isPresented: $showingSettings, content: { SettingsView() }) .padding() } } struct SettingsView: View { @Environment(\.dismiss) private var dismiss @State private var selectedFolder: Folder? = nil private var folders = [Folder(name: "Recents"), Folder(name: "Deleted"), Folder(name: "Custom")] var body: some View { NavigationSplitView { SidebarView(selectedFolder: $selectedFolder, folders: folders) } detail: { VStack { if let folder = selectedFolder { Text(folder.name) } else { Text("No selection") } } .toolbar { ToolbarItem(placement: .cancellationAction) { Button { dismiss() } label: { Text("Cancel") } } ToolbarItem(placement: .confirmationAction) { Button { dismiss() } label: { Text("Save") } } } } } } struct SidebarView: View { @Binding var selectedFolder: Folder? var folders: [Folder] var body: some View { List(selection: $selectedFolder) { ForEach(folders) { folder in NavigationLink(value: folder) { Text(folder.name) } } } } } Steps to reproduce the issue: Launch the attached project on an iPad or iPad simulator Tap the Settings button Select one item in the sidebar Use the app switcher to open an other app or just leave the app Bring back the app Result: Both Cancel and Save buttons are gone. Note: This will not occur if no item is selected in the sidebar. FB12991687
4
0
1.9k
Jan ’24
SwiftUI TextEditor on Mac, spell check weirdness
I think I'm misunderstanding something here, maybe someone could point me in the right direction. In System Settings, "Correct spelling automatically" is DISABLED, along with all the other options that ruin what you're typing. In TextEdit, it continues to highlight spelling and grammar mistakes, so does Mail, Safari and others. Yet SwiftUI made apps, don't. I can right-click, enable "Check Spelling while typing", but after typing a few characters, words, it becomes disabled again. I've busted through the view hierarchy to get the hosted NSTextView and overridden "isContinuousSpellCheckingEnabled" but something frequently reverts this to false. Is my only option to have a large TextEditor with spell checking (but not auto correction) to create my own version of TextEditor by hosting the NSTextView myself. That's a lot of work for something which seems wrong, when I'm hoping that I'm simply missing something here. Xcode 15.2 on macOS 13.5.
1
1
685
Jan ’24
Unwanted "More" button in tabView when selected tab is in 5th position and beyond
Hello SwiftUI devs, I would like to remove the "More" button that appears in the top left of the screen whenever the selected tab of a tab view is in 5th position and beyond. It ruins the layout. struct ContentView: View { private let tabs = (1...10).map { "\($0)" } @State private var selectedTab: String = "5" var body: some View { TabView(selection: $selectedTab) { ForEach(tabs, id: \.self) { tab in Text("Tab \(tab)") .tabItem { Label("Tab \(tab)", systemImage: "star") } .toolbar(.hidden, for: .tabBar) } } } } At first glance, one easy fix would be to rearrange the tabs list in the ForEach loop, putting the selected tab at the first position. This does the trick BUT we lose the states of the views, which is out of the question in my use-case. Getting rid of the tab view and handling the logic with a simple Switch paired with a state restoration mechanism using SceneStorage or SwiftData is probably possible but sounds like a white elephant compared to finding a solution to remove that "More" button. Thank you
1
1
588
Jan ’24
SwiftUi Picker in WatchOS throws Scrollview Error when using Digital Crown
The following WatchOs App example is very short, but already not functioning as it is expected, when using Digital Crown (full code): import SwiftUI struct ContentView: View { let array = ["One","Two","Three","Four"] @State var selection = "One" var body: some View { Picker("Array", selection: $selection) { ForEach(array, id: \.self) { Text($0) } } } } The following 2 errors are thrown, when using Digital Crown for scrolling: ScrollView contentOffset binding has been read; this will cause grossly inefficient view performance as the ScrollView's content will be updated whenever its contentOffset changes. Read the contentOffset binding in a view that is not parented between the creator of the binding and the ScrollView to avoid this. Error: Error Domain=NSOSStatusErrorDomain Code=-536870187 "(null)" Any help appreciated. Thanks a lot.
6
5
1.1k
Jan ’24
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.6k
Feb ’24
Swift unable to find sound file
Hi everyone, I'm currently facing an issue with AVAudioPlayer in my SwiftUI project. Despite ensuring that the sound file "buttonsound.mp3" is properly added to the project's resources (I dragged and dropped it into Xcode), the application is still unable to locate the file when attempting to play it. Here's the simplified version of the code I'm using: import SwiftUI import AVFoundation struct ContentView: View { var body: some View { VStack { Button("Play sound") { playSound(named: "buttonsound", ofType: "mp3") } } } } func playSound(named name: String, ofType type: String) { guard let soundURL = Bundle.main.url(forResource: name, withExtension: type) else { print("Sound file not found") return } do { let audioPlayer = try AVAudioPlayer(contentsOf: soundURL) audioPlayer.prepareToPlay() audioPlayer.play() } catch let error { print("Error playing sound: \(error.localizedDescription)") } }
8
0
2.6k
Feb ’24
TextEditor with a fixedSize and scroll disabled is completely broken
I am trying to build a text editor that shrinks to its content size. The closest I have been able to get has been to add the .scrollDisabled(true) and .fixedSize(horizontal: false, vertical: true) modifiers. This almost achieves what I need. There are two problems though: long single line text gets cut off at the end creating line breaks causes the text editor to grow vertically as expected (uncovering the cut off text in point 1 above). However, when you delete the line breaks, the TextEditor does not shrink again. I have had a radar open for some time: FB13292506. Hopefully opening a thread here will get more visibility. And here is some sample code to easily reproduce the issue: import SwiftUI struct ContentView: View { @State var text = "[This is some long text that will be cut off at the end of the text editor]" var body: some View { TextEditor(text: $text) .scrollDisabled(true) .fixedSize(horizontal: false, vertical: true) } } #Preview { ContentView() } Here is a gif of the behavior:
2
2
1.4k
Feb ’24
In iOS 17.4 beta 3, .searchable incorrectly presents keyboard when presenting a sheet
I've submitted this as FB13628591 but I figure a forum post never hurts ;) I’ve discovered an issue with keyboard presentation when using .searchable in SwiftUI in iOS 17.4 beta 3, shown in this video (https://imgur.com/1hmM5u0) running this sample code. struct Animal: Identifiable { var id: String { return name } let name: String } struct ContentView: View { let animals: [Animal] = [.init(name: "Dog"), .init(name: "Cat"), .init(name: "Turtle")] @State var presentedAnimal: Animal? = nil @State var searchText: String = "" var body: some View { NavigationStack { List { ForEach(animals) { item in Button(item.name) { self.presentedAnimal = item } } } .sheet(item: $presentedAnimal) { item in Text(item.name) } .searchable(text: $searchText) } } } As of iOS 17.4, the behavior of the above code is that if you tap one of the list buttons to present a sheet while the keyboard is still presented, the keyboard will dismiss then represent once the sheet is presented. In the video, I tap the “Cat” button while the search keyboard is still presented. This is confusing, because the keyboard actually belongs to the presenting .searchable view, not the presented sheet. In all previous versions, the keyboard would dismiss and stay that way. That is the correct behavior. I’ve noticed this erroneously presented keyboard does not respond to calls to resignFirstResponder: let resign = #selector(UIResponder.resignFirstResponder) UIApplication.shared.sendAction(resign, to: nil, from: nil, for: nil)
5
3
1.7k
Feb ’24
Xcode 15 console logging of system messages
Background I have a SwiftUI app that uses OSLog and the new Logger framework. In my SwiftUI views, I would like to use something like Self._logChanges() to help debug issues. After some trial and error, I can see the messages appear in the System console log for the app I am debugging using the com.apple.SwiftUI subsystem. Problem I'd like to see those same messages directly in Xcode's console window so I can filter them as needed. How do I do that? Thanks! -Patrick
4
1
2.3k
Feb ’24
Does some restriction exist in SwiftUI for binding computed values?
I have a view, and in this view I bind Axis class values — lowerBound which is a regular property and at – computed one which comes from protocol HasPositionProtocol associated with Axis. struct AxisPropertiesView<Axis>: View where Axis: StyledAxisProtocol, Axis: HasPositionProtocol, Axis: Observable { @Bindable var axis: Axis var body: some View { HStack { TextField("", text: $axis.shortName) .frame(width: 40) TextField("", value: $axis.lowerBound, format: .number) .frame(width: 45) //Problem is here: Slider(value: $axis.at, in: axis.bounds) ... Unfortunately I got en error Failed to produce diagnostic for expression; ... for whole View. But if I remove Slider from View, error disappeared. What could cause this strange behaviour? Value of .at comes from: public extension HasPositionProtocol { ///Absolut position on Axis var at: Double { get { switch position { case .max: return bounds.upperBound case .min: return bounds.lowerBound case .number(let number): return number } } set { switch newValue { case bounds.lowerBound: position = .min case bounds.upperBound: position = .max default: position = .number(newValue) } } } }
1
0
380
Feb ’24
Keyboard will not show when setting focus on a SwiftUI text field from a button in an ornament on visionOS
Using a button that is placed in the bottom ornament to set focus on a text field will not display the keyboard properly while a button embedded in the view will behave as expected. To demonstrate the issue, simply run the attached project on Vision Pro with visionOS 1.1 and tap the Toggle 2 button in the bottom ornament. You’ll see that the field does have focus but the keyboard is now visible. Run the same test with Toggle 1 and the field will get focus and the keyboard will show as expected. import SwiftUI import RealityKit import RealityKitContent struct ContentView: View { @State private var text = "" @State private var showKeyboard = false @FocusState private var focusedField: FocusField? private enum FocusField: Hashable { case username case password } var body: some View { VStack { TextField("Test", text: $text) .focused($focusedField, equals: .username) Text("Entered Text: \(text)") .padding() Button("Toggle 1") { // This button will work and show the keyboard if focusedField != nil { focusedField = nil } else { focusedField = .username } } Spacer() } .padding() .toolbar { ToolbarItem(placement: .bottomOrnament) { Button("Toggle 2") { // This button will set focus properly but not show the keyboard if focusedField != nil { focusedField = nil } else { focusedField = .username } } } } } } Is there a way to work around this? FB13641609
1
0
718
Feb ’24
StoreKit's manageSubscriptionsSheet view modifier not loading
Our app was just rejected by Apple because they say the subscription management sheet never loads. It just spins indefinitely. We're using StoreKit's manageSubscriptionsSheet view modifier to present the sheet, and it's always worked for us when testing in SandBox. Has anyone else had this problem? Given that it's Apple's own code that got us rejected, what's our path forward?
9
5
1.2k
Feb ’24
SubscriptionStoreView showing 'The subscription is unavailable in the current storefront.' in production (StoreKit2)
I Implement a 'SubscriptionStoreView' using 'groupID' into a project (iOS is targeting 17.2 and macOS is targeting 14.1).Build/run the application locally (both production and development environments will work fine), however once the application is live on the AppStore in AppStoreConnect, SubscriptionStoreView no longer shows products and only shows 'Subscription Unavailable' and 'The subscription is unavailable in the current storefront.' - this message is shown live in production for both iOS and macOS targets. There is no log messages shown in the Console that indicate anything going wrong with StoreKit 2, but I haven't made any changes to my code and noticed this first start appearing about 5 days ago. I expect the subscription store to be visible to all users and for my products to display. My application is live on both the iOS and macOS AppStores, it passed App Review and I have users who have previously been able to subscribe and use my application, I have not pushed any new changes, so something has changed in StoreKit2 which is causing unexpected behaviour and for this error message to display. As 'SubscriptionStoreView' is a view provided by Apple, I'm really not sure on the pathway forward other than going back to StoreKit1 which I really don't want to do. Is there any further error information that can be provided on what might be causing this and how I can fix it? (I have created a feedback ticket FB13658521)
4
2
1.7k
Feb ’24
SignInWithApple / AuthenticationServices fails SwiftUI
Xcode 15.2, iOS 17.2 I have a piece of code that displays videos. It has been working for at least 6 months. Suddenly only the first video played. The following videos would only play audio with the video being frozen at the first frame. I noticed that SwiftUI would start to instantiate multiple instances of my player observable class instead of just one. After chasing the problem for most of a day I found that if I completely removed every piece of code referencing AuthenticationServices then everything would work fine again. Even if I add the following piece of code which is not used or called in any way. Then SwiftUI will start to act weird. func configure(_ request: ASAuthorizationAppleIDRequest) { request.requestedScopes = [.fullName, .email] } If I comment out request.requestedScopes = [.fullName, .email] everything works fine. The SignInWithApple is configured and works fine if I enable the code. Any suggestions on how to solve or any work arounds would be highly appreciated.
1
0
926
Feb ’24