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

A Summary of the WWDC25 Group Lab - UI Frameworks
At WWDC25 we launched a new type of Lab event for the developer community - Group Labs. A Group Lab is a panel Q&A designed for a large audience of developers. Group Labs are a unique opportunity for the community to submit questions directly to a panel of Apple engineers and designers. Here are the highlights from the WWDC25 Group Lab for UI Frameworks. How would you recommend developers start adopting the new design? Start by focusing on the foundational structural elements of your application, working from the "top down" or "bottom up" based on your application's hierarchy. These structural changes, like edge-to-edge content and updated navigation and controls, often require corresponding code modifications. As a first step, recompile your application with the new SDK to see what updates are automatically applied, especially if you've been using standard controls. Then, carefully analyze where the new design elements can be applied to your UI, paying particular attention to custom controls or UI that could benefit from a refresh. Address the large structural items first then focus on smaller details is recommended. Will we need to migrate our UI code to Swift and SwiftUI to adopt the new design? No, you will not need to migrate your UI code to Swift and SwiftUI to adopt the new design. The UI frameworks fully support the new design, allowing you to migrate your app with as little effort as possible, especially if you've been using standard controls. The goal is to make it easy to adopt the new design, regardless of your current UI framework, to achieve a cohesive look across the operating system. What was the reason for choosing Liquid Glass over frosted glass, as used in visionOS? The choice of Liquid Glass was driven by the desire to bring content to life. The see-through nature of Liquid Glass enhances this effect. The appearance of Liquid Glass adapts based on its size; larger glass elements look more frosted, which aligns with the design of visionOS, where everything feels larger and benefits from the frosted look. What are best practices for apps that use customized navigation bars? The new design emphasizes behavior and transitions as much as static appearance. Consider whether you truly need a custom navigation bar, or if the system-provided controls can meet your needs. Explore new APIs for subtitles and custom views in navigation bars, designed to support common use cases. If you still require a custom solution, ensure you're respecting safe areas using APIs like SwiftUI's safeAreaInset. When working with Liquid Glass, group related buttons in shared containers to maintain design consistency. Finally, mark glass containers as interactive. For branding, instead of coloring the navigation bar directly, consider incorporating branding colors into the content area behind the Liquid Glass controls. This creates a dynamic effect where the color is visible through the glass and moves with the content as the user scrolls. I want to know why new UI Framework APIs aren’t backward compatible, specifically in SwiftUI? It leads to code with lots of if-else statements. Existing APIs have been updated to work with the new design where possible, ensuring that apps using those APIs will adopt the new design and function on both older and newer operating systems. However, new APIs often depend on deep integration across the framework and graphics stack, making backward compatibility impractical. When using these new APIs, it's important to consider how they fit within the context of the latest OS. The use of if-else statements allows you to maintain compatibility with older systems while taking full advantage of the new APIs and design features on newer systems. If you are using new APIs, it likely means you are implementing something very specific to the new design language. Using conditional code allows you to intentionally create different code paths for the new design versus older operating systems. Prefer to use if #available where appropriate to intentionally adopt new design elements. Are there any Liquid Glass materials in iOS or macOS that are only available as part of dedicated components? Or are all those materials available through new UIKit and AppKit views? Yes, some variations of the Liquid Glass material are exclusively available through dedicated components like sliders, segmented controls, and tab bars. However, the "regular" and "clear" glass materials should satisfy most application requirements. If you encounter situations where these options are insufficient, please file feedback. If I were to create an app today, how should I design it to make it future proof using Liquid Glass? The best approach to future-proof your app is to utilize standard system controls and design your UI to align with the standard system look and feel. Using the framework-provided declarative API generally leads to easier adoption of future design changes, as you're expressing intent rather than specifying pixel-perfect visuals. Pay close attention to the design sessions offered this year, which cover the design motivation behind the Liquid Glass material and best practices for its use. Is it possible to implement your own sidebar on macOS without NSSplitViewController, but still provide the Liquid Glass appearance? While technically possible to create a custom sidebar that approximates the Liquid Glass appearance without using NSSplitViewController, it is not recommended. The system implementation of the sidebar involves significant unseen complexity, including interlayering with scroll edge effects and fullscreen behaviors. NSSplitViewController provides the necessary level of abstraction for the framework to handle these details correctly. Regarding the SceneDelagate and scene based life-cycle, I would like to confirm that AppDelegate is not going away. Also if the above is a correct understanding, is there any advice as to what should, and should not, be moved to the SceneDelegate? UIApplicationDelegate is not going away and still serves a purpose for application-level interactions with the system and managing scenes at a higher level. Move code related to your app's scene or UI into the UISceneDelegate. Remember that adopting scenes doesn't necessarily mean supporting multiple scenes; an app can be scene-based but still support only one scene. Refer to the tech note Migrating to the UIKit scene-based life cycle and the Make your UIKit app more flexible WWDC25 session for more information.
Topic: UI Frameworks SubTopic: General
0
0
803
Jun ’25
Live Q&A Summary - SwiftUI foundations: Build great apps with SwiftUI
Here’s a recap of the Live Q&A for SwiftUI foundations: Build great apps with SwiftUI. If you participated and asked questions, thank you for coming and participating! If you weren’t able to join us live we hope this recap is useful Where can I watch the VOD? Is the sample code “Wishlist” that was shown available for download? You can view the replay of the entire event here https://www.youtube.com/watch?v=Z3vloOtZLkQ The sample code for the Wishlist app will be made available in the coming weeks on the Apple Developer website, we'll send an update via email when it is available. What are the best practices when it comes to building complex navigations in SwiftUI? The developer website has documentation on navigation style best practices. Explore navigation basics like NavigationStack and TabView to get a ground-up understanding. For documentation on navigation APIs see Navigation. How can I integrate UIKit with my SwiftUI app? What about adding SwiftUI into my UIKit app? See UIKit integration: Add UIKit views to your SwiftUI app, or use SwiftUI views in your UIKit app. Both UIKit and SwiftUI provide API to show a view hierarchy of the other. For UIKit to SwiftUI, you would use UIViewControllerRepresentable. For SwiftUI to UIKit, you would use UIHostingController. Landmarks: Interfacing with UIKit walks you through step by step how to implement UIKit in SwiftUI with UIViewControllerRepresentable, and this WWDC22 video demonstrates UIHostingController, for those that want to add SwiftUI to their UIKit. Does Wishlist feature a new iOS 26 font? How can I add custom fonts and text of my app? We’re glad to hear many of you liked wide text shown in Wishlist, however, It is the default system font with some light SwiftUI styling! Check it out for yourself in the sample code when made available, and you can learn more about customizing fonts and text by seeing Font and Applying custom fonts to text. Does Xcode have a dependency graph we can use to optimize our SwiftUI Views? Xcode comes with Instruments. Instruments is the best way to figure out what is causing excessive updates and other issues with performance. That link provides direct tutorials and resources for how to use and understand. Previews also have many useful tools for analyzing SwiftUI views, for more info see Previews in Xcode Check out this video from our latest WWDC Optimize SwiftUI performance with Instruments for information on how to use Instruments to profile and optimize your app with real-world applications If you still have questions, Check out the Instruments section of these forums and create a post so the community has the opportunity to help guide you. Are there UI debugging tools to help diagnose layout issues? Yes, Xcode also features a View Debugger located by selecting the View Debug Hierarchy, pictured below. Use the View Debugger to capture and inspect your view hierarchy, identifying which views affect window sizing. The SwiftUI Inspector also lets you examine view frames and layout behavior. See Diagnosing issues in the appearance of a running app to learn about debugging visual and layout issues. As an absolute beginner, what would be the first go-to step to go for training? Do I need prior knowledge of frameworks to get started with SwiftUI? A great place to learn how to develop for Apple platforms is with Pathways! Many developers start with Develop in Swift tutorials, which exposes you to several frameworks while teaching you the basics of SwiftUI. When you're ready to take your learning further, you can read the documentation for the specific frameworks that interest you at https://developer.apple.com/documentation/.
Topic: UI Frameworks SubTopic: SwiftUI
2
0
67
2d
SwiftData crash when using a @Query on macOS 15.3.x
We use @Query macro in our App. After we got macOS 15.3 update, our App crashes at @Query line. SwiftData/Schema.swift:305: Fatal error: KeyPath \Item.<computed 0x0000000100599e54 (Vec3D)>.x points to a field (<computed 0x0000000100599e54 (Vec3D)>) that is unknown to Item and cannot be used. This problem occurs only when the build configuration is "Release", and only when I use @Query macro with sort: parameter. The App still works fine on macOS 14.7.3. This issue seems similar to what has already been reported in the forum. It looks like a regression on iOS 18.3. https://developer.apple.com/forums/thread/773308 Item.swift import Foundation import SwiftData public struct Vec3D { let x,y,z: Int } extension Vec3D: Codable { } @Model final class Item { var timestamp: Date var vec: Vec3D init(timestamp: Date) { self.timestamp = timestamp self.vec = Vec3D(x: 0, y: 0, z: 0) } } ContentView.Swift import SwiftUI import SwiftData struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query(sort: \Item.vec.x) // Crash private var items: [Item] var body: some View { NavigationSplitView { List { ForEach(items) { item in NavigationLink { Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))") } label: { Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) } } .onDelete(perform: deleteItems) } .navigationSplitViewColumnWidth(min: 180, ideal: 200) .toolbar { ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } detail: { Text("Select an item") } } private func addItem() { withAnimation { let newItem = Item(timestamp: Date()) modelContext.insert(newItem) } } private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(items[index]) } } } }
1
0
479
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
399
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
319
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
366
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
367
Feb ’25
.fileImporter not working on iPhone
I've been running into an issue using .fileImporter in SwiftUI already for a year. On iPhone simulator, Mac Catalyst and real iPad it works as expected, but when it comes to the test on a real iPhone, the picker just won't let you select files. It's not the permission issue, the sheet won't close at all and the callback isn't called. At the same time, if you use UIKits DocumentPickerViewController, everything starts working as expected, on Mac Catalyst/Simulator/iPad as well as on a real iPhone. Steps to reproduce: Create a new Xcode project using SwiftUI. Paste following code: import SwiftUI struct ContentView: View { @State var sShowing = false @State var uShowing = false @State var showAlert = false @State var alertText = "" var body: some View { VStack { VStack { Button("Test SWIFTUI") { sShowing = true } } .fileImporter(isPresented: $sShowing, allowedContentTypes: [.item]) {result in alertText = String(describing: result) showAlert = true } VStack { Button("Test UIKIT") { uShowing = true } } .sheet(isPresented: $uShowing) { DocumentPicker(contentTypes: [.item]) {url in alertText = String(describing: url) showAlert = true } } .padding(.top, 50) } .padding() .alert(isPresented: $showAlert) { Alert(title: Text("Result"), message: Text(alertText)) } } } DocumentPicker.swift: import SwiftUI import UniformTypeIdentifiers struct DocumentPicker: UIViewControllerRepresentable { let contentTypes: [UTType] let onPicked: (URL) -> Void func makeCoordinator() -> Coordinator { Coordinator(self) } func makeUIViewController(context: Context) -> UIDocumentPickerViewController { let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true) documentPicker.delegate = context.coordinator documentPicker.modalPresentationStyle = .formSheet return documentPicker } func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {} class Coordinator: NSObject, UIDocumentPickerDelegate { var parent: DocumentPicker init(_ parent: DocumentPicker) { self.parent = parent } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { print("Success!", urls) guard let url = urls.first else { return } parent.onPicked(url) } func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { print("Picker was cancelled") } } } Run the project on Mac Catalyst to confirm it working. Try it out on a real iPhone. For some reason, I can't attach a video, so I can only show a screenshot
1
0
464
Feb ’25
Unable to delete CKShare
Running the Apple sample code “Sharing Core Data objects between iCloud users” has presented the following challenge: After the creation of a CKRecord in a Persistent CloudKit Container private database, the owner then shares it to a participant. All works fine. Then the Owner wants to stop sharing. That's fine too, although the CKRecord remains within the same shared zone within the owner's private database; it doesn't move back to the private database. Then the owner wants to delete the CKRecord completely. Deletion of the record works, but evidence of the CKShare within the shared zone still remains inside the owner's private database. It is clearly visible on the CloudKit dashboard. Probably doesn’t take up much memory but v messy and not cool. How to delete this CKShare completely, leaving no trace? Any ideas would be most gratefully received!
1
0
594
Feb ’25
Mac Catalyst: Presenting view controller <UIAlertController:> from detached view controller <MyViewController:> is not supported, and may result in incorrect safe area insets and a corrupt root presentation on Sonoma
Okay so I'm getting this log every time I present a UIAlertController: Mac Catalyst: Presenting view controller <UIAlertController: 0x10f027000> from detached view controller <MyViewController: 0x10d104080> is not supported, and may result in incorrect safe area insets and a corrupt root presentation. Make sure <MyViewController: 0x10d104080> is in the view controller hierarchy before presenting from it. Will become a hard exception in a future release. A few points: MyViewController is not detached and the presentation shows just fine. I specifically check for this before presenting the alert controller like so: BOOL okayToPresentError = (self.isViewLoaded && self.view.window != nil); if (okayToPresentError) { [self presentErrorInAlertController:error]; } else { //Wait until view did appear. self.errorToPresentInViewDidAppear = error; } It spews out every time an error is fed back to my app and I present the alert controller (I can turn off the network connection and I show an alert controller with a "retry" button in it which will loop the error back so I can replay the error alert presentation over and over again) . Every time the alert controller is presented, I get this spewing in the console. Please don't start throwing hard exceptions because the check is faulty.
4
1
2.3k
Feb ’25
SwiftUI: Sheet presented from List row is not removed from screen when row is removed
I noticed if I show a sheet from a List row, then remove the row the sheet isn't removed from the screen like it is if using VStack or LazyVStack. I'd be interested to know the reason why the sheet isn't removed from the screen in the code below. It only occurs with List/Form. VStack/LazyVStack gives the expected result. I was wondering if it is an implementation issue, e.g. since List is backed by UICollectionView maybe the cells can't be the presenter of the sheet for some reason. Launch on iPhone 16 Pro Simulator iOS 18.2 Tap "Show Button" Tap "Show Sheet" What is expected: The sheet should disappear after 5 seconds. And I don't mean it should dismiss, I just mean removed from the screen. Similarly if the View that showed the sheet was re-added and its show @State was still true, then the sheet would be added back to the screen instantly without presentation animation. What actually happens: Sheet remains on screen despite the row that presented the sheet being removed. Xcode 16.2 iOS Simulator 18.2. struct ContentView: View { @State var showButton = false var body: some View { Button("\(showButton ? "Hide" : "Show" ) Button") { showButton = true Task { try? await Task.sleep(for: .seconds(5)) self.showButton = false } } //LazyVStack { // does not have this problem List { if showButton { SheetButton() } } } } struct SheetButton: View { @State var sheet = false @State var counter = 0 var body: some View { Text(counter, format: .number) Button("\(sheet ? "Hide" : "Show") Sheet") { counter += 1 sheet.toggle() } .sheet(isPresented: $sheet) { Text("Wait... This should auto-hide in 5 secs. Does not with List but does with LazyVStack.") Button("Hide") { sheet = false } .presentationDetents([.fraction(0.3)]) } // .onDisappear { sheet = false } // workaround } } I can work around the problem with .onDisappear { sheet = false } but I would prefer the behaviour to be consistent across the container controls.
2
0
398
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
Crash in __UIKitSharedArtworkManager
Hi, We have received reports about crash when creating a UIButton: let button = UIButton(type: .infoLight) The exception is bad access: Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000074 Exception Codes: 0x0000000000000001, 0x0000000000000074 VM Region Info: 0x74 is not in any region. Bytes before following region: 4298211212 REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL UNUSED SPACE AT START ---> __TEXT 100318000-100324000 [ 48K] r-x/r-x SM=COW /var/containers/Bundle/Application/E8912E1B-FFD8-49AF-A78A-7AA8805FDB95/My App/My App Termination Reason: SIGNAL 11 Segmentation fault: 11 Terminating Process: exc handler [550] and the main thread is crashing with the following stack trace: Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 UIKitCore 0x197e27a58 ____UIKitSharedArtworkManager_block_invoke + 116 1 libdispatch.dylib 0x19cfe2fa8 _dispatch_client_callout + 20 2 libdispatch.dylib 0x19cfe47f4 _dispatch_once_callout + 32 3 UIKitCore 0x197c3bb10 __UIKitSharedArtworkManager + 64 4 UIKitCore 0x197c3b5b0 _UIImageWithNameAndTraitCollection + 172 5 UIKitCore 0x197cbc180 _UIImageWithName + 44 6 UIKitCore 0x197c3be80 +[UIImage _systemImageNamed:fallback:withConfiguration:] + 132 7 UIKitCore 0x197a8c550 +[UIButton _defaultImageForType:andState:withConfiguration:] + 360 8 UIKitCore 0x197c1bc38 +[UIButton buttonWithType:] + 124 9 MapboxMaps 0x105f23fdc InfoButtonOrnament.init() + 400 10 MapboxMaps 0x105f2424c @objc InfoButtonOrnament.init() + 20 11 MapboxMaps 0x105fd8d80 MapView.setupManagers() + 1476 12 MapboxMaps 0x105fd8788 MapView.commonInit(mapInitOptions:overridingStyleURI:) + 1284 13 MapboxMaps 0x105fe2bcc specialized MapView.init(frame:mapInitOptions:) + 1500 14 MapboxMaps 0x105fd78cc MapView.init(frame:mapInitOptions:) + 20 15 mapbox_maps_flutter 0x10858c1dc MapboxMapController.init(withFrame:mapInitOptions:channelSuffix:registrar:pluginVersion:eventTypes:) + 496 16 mapbox_maps_flutter 0x10858f274 specialized MapboxMapFactory.create(withFrame:viewIdentifier:arguments:) + 2312 17 mapbox_maps_flutter 0x10858e8e8 @objc MapboxMapFactory.create(withFrame:viewIdentifier:arguments:) + 128 18 Flutter 0x10a99eb88 0x10a980000 + 125832 19 Flutter 0x10af474bc 0x10a980000 + 6059196 20 Flutter 0x10a9c3d38 0x10a980000 + 277816 21 libdispatch.dylib 0x19cfe1248 _dispatch_call_block_and_release + 32 22 libdispatch.dylib 0x19cfe2fa8 _dispatch_client_callout + 20 23 libdispatch.dylib 0x19cff1a34 _dispatch_main_queue_drain + 984 24 libdispatch.dylib 0x19cff164c _dispatch_main_queue_callback_4CF + 44 25 CoreFoundation 0x19529abcc __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 26 CoreFoundation 0x1952971c0 __CFRunLoopRun + 1996 27 CoreFoundation 0x1952e9284 CFRunLoopRunSpecific + 588 28 GraphicsServices 0x1e25554c0 GSEventRunModal + 164 29 UIKitCore 0x197e32674 -[UIApplication _run] + 816 30 UIKitCore 0x197a58e88 UIApplicationMain + 340 31 My App 0x1003244e8 main + 64 32 dyld 0x1bb541de8 start + 2724 Has anyone experienced this? Could it be a bug in UIKit? Cheers, Roman Laitarenko
Topic: UI Frameworks SubTopic: UIKit
4
0
345
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
486
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
403
Feb ’25
SwiftUI @Observable Causes Extra Initializations When Using Reference Type Properties
I've encountered an issue where using @Observable in SwiftUI causes extra initializations and deinitializations when a reference type is included as a property inside a struct. Specifically, when I include a reference type (a simple class Empty {}) inside a struct (Test), DetailsViewModel is initialized and deinitialized twice instead of once. If I remove the reference type, the behavior is correct. This issue does not occur when using @StateObject instead of @Observable. Additionally, I've submitted a feedback report: FB16631081. Steps to Reproduce Run the provided SwiftUI sample code (tested on iOS 18.2 & iOS 18.3 using Xcode 16.2). Observe the console logs when navigating to DetailsView. Comment out var empty = Empty() in the Test struct. Run again and compare console logs. Change @Observable in DetailsViewModel to @StateObject and observe that the issue no longer occurs. Expected Behavior The DetailsViewModel should initialize once and deinitialize once, regardless of whether Test contains a reference type. Actual Behavior With var empty = Empty() present, DetailsViewModel initializes and deinitializes twice. However, if the reference type is removed, or when using @StateObject, the behavior is correct (one initialization, one deinitialization). Code Sample import SwiftUI enum Route { case details } @MainActor @Observable final class NavigationManager { var path = NavigationPath() } struct ContentView: View { @State private var navigationManager = NavigationManager() var body: some View { NavigationStack(path: $navigationManager.path) { HomeView() .environment(navigationManager) } } } final class Empty { } struct Test { var empty = Empty() // Comment this out to make it work } struct HomeView: View { private let test = Test() @Environment(NavigationManager.self) private var navigationManager var body: some View { Form { Button("Go To Details View") { navigationManager.path.append(Route.details) } } .navigationTitle("Home View") .navigationDestination(for: Route.self) { route in switch route { case .details: DetailsView() .environment(navigationManager) } } } } @MainActor @Observable final class DetailsViewModel { var fullScreenItem: Item? init() { print("DetailsViewModel Init") } deinit { print("DetailsViewModel Deinit") } } struct Item: Identifiable { let id = UUID() let value: Int } struct DetailsView: View { @State private var viewModel = DetailsViewModel() @Environment(NavigationManager.self) private var navigationManager var body: some View { ZStack { Color.green Button("Show Full Screen Cover") { viewModel.fullScreenItem = .init(value: 4) } } .navigationTitle("Details View") .fullScreenCover(item: $viewModel.fullScreenItem) { item in NavigationStack { FullScreenView(item: item) .navigationTitle("Full Screen Item: \(item.value)") .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel") { withAnimation(completionCriteria: .logicallyComplete) { viewModel.fullScreenItem = nil } completion: { var transaction = Transaction() transaction.disablesAnimations = true withTransaction(transaction) { navigationManager.path.removeLast() } } } } } } } } } struct FullScreenView: View { @Environment(\.dismiss) var dismiss let item: Item var body: some View { ZStack { Color.red Text("Full Screen View \(item.value)") .navigationTitle("Full Screen View") } } } Console Output With var empty = Empty() in Test DetailsViewModel Init DetailsViewModel Init DetailsViewModel Deinit DetailsViewModel Deinit Without var empty = Empty() in Test DetailsViewModel Init DetailsViewModel Deinit Using @StateObject Instead of @Observable DetailsViewModel Init DetailsViewModel Deinit Additional Notes This issue occurs only when using @Observable. Switching to @StateObject prevents it. This behavior suggests a possible issue with how SwiftUI handles reference-type properties inside structs when using @Observable. Using a struct-only approach (removing Empty class) avoids the issue, but that’s not always a practical solution. Questions for Discussion Is this expected behavior with @Observable? Could this be an unintended side effect of SwiftUI’s state management? Are there any recommended workarounds apart from switching to @StateObject? Would love to hear if anyone else has run into this or if Apple has provided any guidance!
0
0
348
Feb ’25
UIHostingController crash when added as child controller on iOS 15
Hello, We are trying to move the UIKit component which is a SwiftUI component. Since our HomeScreenViewController is subclass of UIViewController we have used UIHostingController to embed this SwiftUI view by adding the hosting view controller’s sub view to HomeScreenViewController’s view’s subview which is UIStackView and also by adding the UIHostingController as the child controller of HomeScreenViewController. This works fine on iOS 16+. But it is causing the following issues on iOS 15. Unable to activate constraint with anchors <NSLayoutYAxisAnchor:0x2807ac740 "UIStackView:0x122b0caf0.bottom"> and <NSLayoutYAxisAnchor:0x2804ff600 "TtGC7SwiftUI14_UIHostingViewV7Loyalty15LargeBannerView:0x135930690.bottom"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal. It crashes with the above exception inside [UIHostingController viewWillAppear] where it is trying to set some constraints in side navigationBarHidden method. Also it is messing up the navigation bar hidden status. Could you please help us with this? But this issue will not come if we don’t add UIHostingController as child of our home screen controller and only add UIHostingController’s view as subview. Please find the attached screenshot for the stack trace. Could you please help us with this. Thanks
Topic: UI Frameworks SubTopic: SwiftUI
2
0
208
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.8k
Feb ’25
iPAD custom in app keyboard stopped responding
IOS 12 - 18.1.1 - objective C, Xcode 16.0 App runs on both iPhone and iPad, this issue only occurs happens on iPads. For the iPhones I am able to get a decent numeric only keyboard to display. I pulled down NumericKeypad from GitHub and used that a model on how to implement a custom keypad. In the inputView of the delegate, a new custom text field is create and then assigned a delegate and other properties then it returns the view to the main ViewController. When the ViewControllers and the correct text field is entered my custom keyboard display and the buttons respond but nothing is displayed in the text field. This has worked for years and all of the sudden it stopped. The original project for the example 10 key custom keyboard builds and when loaded that works on the iPad. If I comment out condition to only execute if running on an iPad and test with an iPhone the keyboards works. It is only on a iPad that this happens. This is the cod that creates creates the keyboard from a .xib file. I am using a storyboard for the main app. #import "Numeric10KeyTextField.h" #import "Numeric10KeyViewController.h" @implementation Numeric10KeyTextField (UIView *)inputView { UIView *view = nil; Numeric10KeyViewController *numVC; // Add hook here for iPhone or other devices if needed but now return nil if iPhone so it uses the default // if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { numVC = [[Numeric10KeyViewController alloc] initWithNibName:@"Numeric10Key" bundle:nil]; [numVC setActionSubviews:numVC.view]; numVC.delegate = self.numeric10KeyDelegate; numVC.numpadTextField = self; view = numVC.view; // } return view; } @end
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
466
Feb ’25
Does LazyVStack and LazyVGrid release views from memory inside a ScrollView?
I am using LazyVStack inside a ScrollView. I understand that lazy views are rendered only when they come into view. However, I haven’t heard much about memory deallocation. I observed that in iOS 18 and later, when scrolling up, the bottom-most views are deallocated from memory, whereas in iOS 17, they are not (Example 1). Additionally, I noticed a similar behavior when switching views using a switch. When switching views by pressing a button, the view was intermittently deinitialized. (Example 2). Example 1) struct ContentView: View { var body: some View { ScrollView { LazyVStack { ForEach(0..<40) { index in CellView(index: index) } } } .padding() } } struct CellView: View { let index: Int @StateObject var viewModel = CellViewModel() var body: some View { Rectangle() .fill(Color.accentColor) .frame(width: 300, height: 300) .overlay { Text("\(index)") } .onAppear { viewModel.index = index } } } class CellViewModel: ObservableObject { @Published var index = 0 init() { print("init") } deinit { print("\(index) deinit") } } #Preview { ContentView() } Example 2 struct ContentView: View { @State var index = 0 var body: some View { LazyVStack { Button(action: { if index > 5 { index = 0 } else { index += 1 } }) { Text("plus index") } MidCellView(index: index) } .padding() } } struct MidCellView: View { let index: Int var body: some View { switch index { case 1: CellView(index: 1) case 2: CellView(index: 2) case 3: CellView(index: 3) case 4: CellView(index: 4) default: CellView(index: 0) } } } struct CellView: View { let index: Int @StateObject var viewModel = CellViewModel() var body: some View { Rectangle() .fill(Color.accentColor) .frame(width: 300, height: 300) .overlay { Text("\(index)") } .onAppear { viewModel.index = index } } } class CellViewModel: ObservableObject { @Published var index = 0 init() { print("init") } deinit { print("\(index) deinit") } } -------------------- init init init init init 2 deinit 3 deinit 4 deinit init
Topic: UI Frameworks SubTopic: SwiftUI
2
0
362
Feb ’25