Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.

All subtopics
Posts under UI Frameworks topic

Post

Replies

Boosts

Views

Activity

SwiftUI ScrollView performance in macOS 15
There seems to be a performance issue when scrolling using the track pad with SwiftUI scroll views in macOS 15. This issue is NOT present in macOS 14. When using the track pad the scrolling is not smooth, but "stutters". However scrolling using the scroll bars is very smooth. The "stuttering" is worse if the SwiftUI ScrollView is in the detail view of a NavigationSplitView. The problem is not noticeable in scroll views with a small number views, but when the more views inside the scroll view, the more prominent the problem becomes. I have a simple example app that illustrates the problem here (the example app is a simplification of my app Yammixer): https://github.com/danwaltin/SwiftUIScrollViewPerformance When running this example app on macOS 14 (Sonoma) on an Intel i7 Mac book pro from 2019 the scrolling is "buttery smooth". But on macOS 15 (Sequoia) on my Apple Silicon M1 Mac book pro the issue is very obvious. When using Instruments I see that on macOS 15 "flame graph" shows that 85% of the execution time is in a "_hitTestForEvent" method. If the test app does not use NavigationSplitView about 70% of execution time is in the _hitTestForEvent method.
Topic: UI Frameworks SubTopic: SwiftUI
16
11
2.4k
Feb ’25
Fatal error: Unexpectedly found nil while unwrapping an Optional value
@IBOutlet weak var surnameTextField: UITextField! surnameTextField.backgroundColor = UIColor.clear surnameTextField.tintColor = .white surnameTextField.textColor = .white surnameTextField.attributedPlaceholder = NSAttributedString(string: surnameTextField.placeholder!, attributes: [NSAttributedString.Key.foregroundColor: UIColor(white: 1.0, alpha: 0.6)]) let bottomLayersurname = CALayer() bottomLayersurname.frame = CGRect(x: 0, y: 29, width:1000, height: 0.6) bottomLayersurname.backgroundColor = UIColor.lightGray.cgColor surnameTextField.layer.addSublayer(bottomLayersurname)
Topic: UI Frameworks SubTopic: UIKit
1
0
348
Feb ’25
How do I properly mix SwiftUI Views with Auto Layout Constraint animations?
I have a SwiftUI View I've introduced to a UIKit app, using UIHostingController. The UIView instance that contains the SwiftUI view is animated using auto layout constraints. In this code block, when a view controller's viewDidAppear method I'm creating the hosting controller and adding its view as a subview of this view controller's view, in addition to doing the Container View Controller dance. override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let hostingViewController = UIHostingController(rootView: TestView()) hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false addChild(hostingViewController) view.addSubview(hostingViewController.view) let centerXConstraint = hostingViewController.view.centerXAnchor.constraint(equalTo: view.centerXAnchor) let topConstraint = hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor) widthConstraint = hostingViewController.view.widthAnchor.constraint(equalToConstant: 361) heightConstraint = hostingViewController.view.heightAnchor.constraint(equalToConstant: 342) NSLayoutConstraint.activate([centerXConstraint, topConstraint, widthConstraint, heightConstraint]) hostingViewController.didMove(toParent: self) self.hostingViewController = hostingViewController } I add a button to the UI which will scale the UIHostingViewController by adjusting its height and width constraints. When it's tapped, this action method runs. @IBAction func animate(_ sender: Any) { widthConstraint.constant = 120.3 heightConstraint.constant = 114.0 UIView.animate(withDuration: 0.5) { self.view.layoutIfNeeded() } } The problem is, the SwiftUI view's contents "jump" at the start of the animation to the final height, then animate into place. I see this both using UIView.animate the UIKit way, or creating a SwiftUI animation and calling `UIView. What else do I need to add to make this animate smoothly?
1
0
467
Feb ’25
Guidelines for ViewThatFits to avoid run-time crashes
TLDR: What rules ensure you won't have sporadic run-time crashes when using ViewThatFits? My app crashes - luckily reproducible. But the code appeared syntacticly and logically correct. Simplified excerpt: https://github.com/alanrick/Experiment3 The crash is caused by ViewThatFits being overwhelmed by concurrent changes in other views, exacerbated by animation effects. In the original code the problem was even worse because I'd gone overboard and used ViewThatFits in sub-views making the whole thing too dynamic. 

 My first rule is: Do not use nested ViewThatFits. 

 But this alone is not sufficient. What other rules can I apply to ensure I won't have hard-to-detect run-time crashes when using ViewThatFits?
Topic: UI Frameworks SubTopic: SwiftUI
2
0
444
Feb ’25
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?
Topic: UI Frameworks SubTopic: SwiftUI
0
0
267
Feb ’25
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
352
Feb ’25
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() }
Topic: UI Frameworks SubTopic: SwiftUI
6
1
933
Feb ’25
UICollectionView.CellRegistration and dequeueConfiguredReusableCell with nil for Item? causes runtime crash
Modern collection views use UICollectionViewDiffableDataSource with UICollectionView.CellRegistration and UICollectionView.dequeueConfiguredReusableCell(registration:indexPath:item). There are runtime crashes when passing nil as argument for the item parameter. There's no clear documentation on whether optional items are allowed or not. The function signature in Swift is: @MainActor @preconcurrency func dequeueConfiguredReusableCell<Cell, Item>(using registration: UICollectionView.CellRegistration<Cell, Item>, for indexPath: IndexPath, item: Item?) -> Cell where Cell : UICollectionViewCell Given the Item? type one would assume Optionals are allowed. In Objective-C the signature is: - (__kindof UICollectionViewCell *)dequeueConfiguredReusableCellWithRegistration:(UICollectionViewCellRegistration *)registration forIndexPath:(NSIndexPath *)indexPath item:(id)item; I'm not sure, if there's implicit nullability bridging to the Swift API or if the Objective-C files has some explicit nullability annotation. The crash is due to a swift_dynamicCast failing with: Could not cast value of type '__SwiftNull' (0x10b1c4dd0) to 'Item' (0x10d6086e0). It's possible to workaround this by making a custom Optional type like enum MyOptional<T> { case nothing case something(T) } and then wrapping and unwrapping Item? to MyOptional<Item>. But this feels like unnecessary boilerplate. With the current situation it's easy to ship an app where everything seems to work, but in production only certain edge cases cause nil values being used and then crashing the app. Please clarify the allowed arguments / types for the dequeueConfiguredReusableCell function. Either Optionals should be supported and not crash at runtime or the signatures should be changed so there's a compile time error, when trying to use an Item?. Feedback: FB16494078
Topic: UI Frameworks SubTopic: UIKit Tags:
3
1
332
Feb ’25
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.8k
Feb ’25
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
300
Feb ’25
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
327
Feb ’25
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() }```
5
2
424
Feb ’25
UITabbarController - padOS18: at top, padOS17 and before: at Bottom
This pertains to iPad apps and UITabbarController in UIKit. Our internal app for employees utilizes UITabbarController displayed at the bottom of the screen. Users prefer to maintain consistency with it being at the bottom. It becomes challenging to argue against this when users point out the iPhone version displaying it "correctly" at the bottom. My response is to trust Apple's design team to keep it at the top. One workaround is to develop the app using the previous Xcode version, version 15 (via Xcode Cloud), targeting padOS17. This ensures the tab bar is shown at the bottom of the screen. However, this approach has its drawbacks: Apple may not support it in the future, leading to missed secure updates for the app, among other issues. Exploring the UITabbarController mode appears to be the solution I am seeking. To quote the documentation "on iPad, If the tabs array contains one or more UITabGroup items, the system displays the content as either a tab bar or a sidebar, depending on the context. Otherwise, it only displays the content only as a tab bar.". The part "displays the content only as a tab bar." made think this is BAU: class ViewController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() self.mode = .tabBar } } Unfortunately, this does not resolve the issue. Is there an API method that can force the tabbar to its previous bottom position? The app uses multiple windows. When we split a window to launch another instance, the tab bar appears at the bottom. This behavior seems tied to the form factor—or potentially to how many items are in the tab bar. We could build a custom tab bar to override this, but that goes against my “don’t reinvent the wheel” principle. Any comments we welcome and thank you for reading this (to the end) Theo
1
0
490
Feb ’25
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
473
Feb ’25
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
395
Feb ’25
Performing simulations in the UI elements in uikit
I wanted to perform simulation in my application as a self tour guide for my user. For this I want to programatically simulate various user interaction events like button click, keypress event in the UITextField or moving the cursor around in the textField. These are only few examples to state, it can be any user interaction event or other events. I wanted to know what is the apple recommendation on how should these simulations be performed? Is there something that apple offers like creating an event which can be directly executed for simulations. Is there some library available for this purpose?
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
316
Feb ’25
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
363
Feb ’25
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
361
Feb ’25