I have a NSViewController as the root view and have a switui view embedded in it via NSHostingView.
override func loadView() {
self.view = NSHostingView(rootView: SwiftUiView())
}
}
In the SwiftUiView, I have a TextField and an NSTextView embedded using NSViewRepresentable, along with a few buttons. There is also a menu:
Menu {
ForEach(menuItems), id: \.self) { item in
Button {
buttonClicked()
} label: {
Text(item)
}
}
} label: {
Image("DropDown")
.contentShape(Rectangle())
.frame(maxWidth: .infinity)
.frame(maxHeight: .infinity)
}
The NSTextView and TextField work fine, and I can type in them until I click on the menu or show an alert. After that, I can no longer place my cursor in the text fields. I am able to select the text but not type in it. When I click on the NSTextView or TextField, nothing happens.
At first, I thought it was just a cursor visibility issue and tried typing, but I received an alert sound. I've been trying to fix this for a couple of days and haven't found any related posts. Any help would be greatly appreciated.
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.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I'm building an app using UITabbarController with 2 tabs: screen A and B. When standing on tab B and I taps on tab A, the order in which the events are triggered will be:
For iOS < 18:
viewWillDisappear() of screen B
tabBarController(_:didSelect:) of UITabbarController
For iOS >= 18:
tabBarController(_:didSelect:) of UITabbarController
viewWillDisappear() of screen B
So my question is this an issue or a new update from Apple on iOS 18.*?
I'm trying to create a form which reads and writes data to a dictionary. when I type something in a field whole form seems to update. Is there anyway to only update the field I'm typing? Android compose have something called SnapshotStateMap which allows smart re-rendering.
Topic:
UI Frameworks
SubTopic:
SwiftUI
The SwiftUI ScrollView lacks some features I need and so I created a custom MyScrollView based on UIScrollView wrapped within a UIViewControllerRepresentable. While this works fine in general I know came across a very strange problem:
When MyScrollView is used in a sheet and its content touches bottom SafeArea, the UI freezes as soon as the should be displayed.
The code below shows the problem as well in preview as on the simulator and on devices. Please note that the code is tuned do the display size of an iPhone 16 Pro. When running on different devices one might need to adjust height of the Color.yellow.
In the demo code the UI freezes if the Color.yellow has a height between 738 to 771 pixels. Every other height is fine.
Is there something wrong with my implementation of MyScrollView? When using ScrollView instead, everything works fine.
Code:
struct ContentView: View {
@State private var showSheet: Bool = false
var body: some View {
ZStack {
Button("Show Sheet") {
showSheet = true
}
}
.sheet(isPresented: $showSheet) {
VStack {
Text("Some Header Content")
MyScrollView {
VStack {
Color.yellow
//.frame(height: 737) // works
.frame(height: 738) // does NOT works
// ...
//.frame(height: 771) // does NOT works
//.frame(height: 772) // works
}
}
.ignoresSafeArea()
}
}
}
}
struct MyScrollView<Content: View>: UIViewControllerRepresentable {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
func makeUIViewController(context: Context) -> UIViewController {
let scrollViewVC = UIViewController()
scrollViewVC.view.backgroundColor = .clear
let scrollView = UIScrollView()
scrollView.backgroundColor = .clear
let contentVC = UIHostingController(rootView: self.content)
contentVC.view.backgroundColor = .clear
context.coordinator.contentVC = contentVC
context.coordinator.scrollView = scrollView
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollViewVC.view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: scrollViewVC.view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: scrollViewVC.view.bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: scrollViewVC.view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: scrollViewVC.view.trailingAnchor)
])
contentVC.willMove(toParent: scrollViewVC)
scrollViewVC.addChild(contentVC)
contentVC.view.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentVC.view)
NSLayoutConstraint.activate([
contentVC.view.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
contentVC.view.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
contentVC.view.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
contentVC.view.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
contentVC.view.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)
])
contentVC.didMove(toParent: scrollViewVC)
return scrollViewVC
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
context.coordinator.contentVC?.rootView = content
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
class Coordinator {
var contentVC: UIHostingController<Content>?
var scrollView: UIScrollView?
init() {
//...
}
}
}
#Preview {
ContentView()
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
Hi,
I have an existing Mac app on the App Store with a couple of widgets as part of the app. I want to now add a new widget to the WidgetBundle. When I build the updated app with Xcode, and then run the updated app, the widgets list doesn't seem to get updated in Notification Center or in the WidgetKit Simulator.
I do have the App Store version installed in the /Applications folder as well, so there might be some conflict. What's the trick to getting the widgets list to run the debug version?
I am experiencing memory leaks in my iOS app that seem to be related to an issue between UIInputView and _UIInputViewContent. After using the memory graph, I'm seeing that instances of these objects aren't being deallocated properly.
The UIInputViewController whichs holds the inputView is being deallocated properly along with its subviews.I have tried to remove all of UIInputViewController's subviews and their functions but the uiInputView is not being deallocated.
The current setup of my app is a collectionView with multiple cells,each possessing a textfield with holds a UIInputViewController.When i scroll up or down,the views are being reused as expected and the number of UIInputViewController stays consistent with the number of textfields.However the number of inputView keeps increasing referencing solely _UIInputViewContent.
class KeyboardViewController: UIInputViewController {
// Callbacks
var key1: ((String) -> Void)?
var key2: (() -> Void)?
var key3: (() -> Void)?
var key4: (() -> Void)?
private lazy var buttonTitles = [
["1", "2", "3"],
["4", "5", "6"],
["7", "8", "9"]
]
override func viewDidLoad() {
super.viewDidLoad()
setupKeyboard()
}
lazy var mainStackView: UIStackView = {
let mainStackView = UIStackView()
mainStackView.axis = .vertical
mainStackView.distribution = .fillEqually
mainStackView.spacing = 16
mainStackView.translatesAutoresizingMaskIntoConstraints = false
return mainStackView
}()
private func setupKeyboard() {
let keyboardView = UIView(frame:CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 279.0))
keyboardView.addSubview(mainStackView)
NSLayoutConstraint.activate([
mainStackView.topAnchor.constraint(equalTo: keyboardView.topAnchor, constant: 16),
mainStackView.leadingAnchor.constraint(equalTo: keyboardView.leadingAnchor, constant: 0),
mainStackView.trailingAnchor.constraint(equalTo: keyboardView.trailingAnchor, constant: -24),
mainStackView.bottomAnchor.constraint(equalTo: keyboardView.bottomAnchor, constant: -35)
])
// Create rows
for (_, _) in buttonTitles.enumerated() {
let rowStackView = UIStackView()
rowStackView.axis = .horizontal
rowStackView.distribution = .fillEqually
rowStackView.spacing = 1
// Create buttons for each row
for title in rowTitles {
let button = createButton(title: title)
rowStackView.addArrangedSubview(button)
}
mainStackView.addArrangedSubview(rowStackView)
}
self.view = keyboardView
}
private func createButton(title: String) -> UIButton {
switch title {
///returns a uibutton based on title
}
}
// MARK: - Button Actions
@objc private func numberTapped(_ sender: UIButton) {
if let number = sender.title(for: .normal) {
key1?(number)
}
}
@objc private func key2Called() {
key2?()
}
@objc private func key3Called() {
key3?()
}
@objc private func key4Called() {
key4?()
}
deinit {
// Clear any strong references
key1 = nil
key2 = nil
key3 = nil
key4 = nil
for subview in mainStackView.arrangedSubviews {
if let stackView = subview as? UIStackView {
for button in stackView.arrangedSubviews {
(button as? UIButton)?.removeTarget(self, action: nil, for: .allEvents)
}
}
}
mainStackView.removeFromSuperview()
}
}
Environment
iOS 16.3
Xcode 18.3.1
Any insights would be greatly appreciated as this is causing noticeable memory growth in my app over time.
I have a few crash report from TestFlight with this context and nothing else. No symbols of my application.
Crash report is attached.
crashlog.crash
It crashes at 16H25 (local time paris) and a few minutes after (8) I see the same user doing task in background (they download data with a particular URL in BGtasks) with a Delay that is consistant with a background wait of 5 or 7 minutes.
I have no more information on this crash and by the way Xcode refuses to load it and shows an error. ( I did a report via Xcode for this).
I am adapting my custom UI Framework for visionOS, and I'm wondering if it is going to be possible to detect hover over different UI elements within my view. The UI Framework draws to a Metal layer in a UIView. I don't currently support uihovergesturerecognizer on the view but I guess this wouldn't help, since you don't get coordinates. I can imagine an unpleasant solution might be to add invisible UIControls for each of my custom controls that are drawn in my own framework.
I config of an alternate icon on the App Store Connect product page optimization. After the app launches, can I retrieve the name of this configured icon through UIApplication.shared.alternateIconName?
Prime Objective
I am trying to have a scroll view with a fixed header, a fixed footer, and a WKWebView in between. Using JavaScript, the height of the webView is determined and set to be large enough to hold the entire content.
The Problem
When selecting text on the webView, the view does not scroll when the edges are reached (this works if the webView is shown without being embedded in a Scroll view, or if it is the last element)
What did I try?
I tried reading the scroll view, or adding a gesture recognizer, but all of that does not work because the selection is essentially a system task
Sourcecode
Sourcecode to demonstrate the issue can be found on GitHub
I'm implementing a custom text editor in SwiftUI using a UITextView wrapped in a UIViewRepresentable. The text editor works for basic text entry, but I'm encountering an issue with scrolling behavior.
When the UITextView becomes the first responder (when tapped), the parent ScrollView doesn't automatically scroll to make the text view visible. Instead, the scroll position jumps to the last known position (scrolls to a different text view that was previously focused).
Here's my implementation reduced to the minimum:
struct SpacedTextEditor: View {
@Binding var text: String
var body: some View {
MinimalEditor(text: $text)
}
}
private struct MinimalEditor: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.backgroundColor = .clear
textView.delegate = context.coordinator
textView.isScrollEnabled = false
textView.text = text
return textView
}
func updateUIView(_ textView: UITextView, context _: Context) {
if textView.text != text {
textView.text = text
}
}
func makeCoordinator() -> Coordinator {
Coordinator(text: $text)
}
class Coordinator: NSObject, UITextViewDelegate {
var text: Binding<String>
init(text: Binding<String>) {
self.text = text
}
func textViewDidChange(_ textView: UITextView) {
text.wrappedValue = textView.text
}
}
}
The text editor is placed inside a ScrollView in my parent view. How can I ensure that when a user taps on the text editor, the ScrollView properly scrolls to make it fully visible or at least it doesn't jump to where the textfield is not even visible?
I need to use a custom textfield because I need to be able to modify the space between lines, and I didn't find a way to do this using the swiftUI component.
Topic:
UI Frameworks
SubTopic:
SwiftUI
There seems to be a bug; when scrolling very quickly down a List, and then scrolling up at normal speed, scrolling becomes very janky and jumpy, often skipping one or two rows. This only happens on macOS.
I'm kind of surprised I've seen no one else mention this bug, as I can recreate it in a very simple Xcode Project. I'm wondering if anyone knows of a workaround?
Steps to reproduce:
Build and launch the code below
Very quickly scroll all the way down using the scrollbar
Scroll up at a normal speed, after a few rows it will get janky
Code:
struct MinimalAlbum: Identifiable {
let id: Int
let title: String
}
struct ContentView: View {
private let staticAlbums: [MinimalAlbum] = (0..<1000).map { i in
MinimalAlbum(id: i, title: "Album Title \(i)")
}
var body: some View {
List {
ForEach(staticAlbums) { album in
Text("Album ID: \(album.id) - \(album.title)")
.frame(height: 80) // Fixed height
}
}
}
}
I have a custom keypad to accept numeric input for iPads that I have been using for many years now. This is longstanding working code. With iOS 18 the touchUpInside (and other) events in the underlying Objective-C modules are not called in the file owner module when activated from the interface. The buttons seem to be properly activated based on the visual cues (they change colors when pressed). This is occurring in both simulators and on hardware. Setting the target OS version does not help. What could the cause and/or solution of this be?
Hello everyone,
I've run into a peculiar behavior with UINavigationController's setViewControllers on iOS 18.2 (I guess it might be reproducible on older versions) when reordering view controllers, and I wonder if anyone can shed some light on this issue.
Initial State: The navigation stack is [A - B - C].
Without Animation: Setting [A - C - B] updates the stack to: A - C - B as expected.
With Animation: Using the same command with animation changes the stack to [A - B], oddly omitting C.
Has anyone else noticed similar behavior or knows why animations might disrupt the stack's update this way? I'd appreciate any insights or suggestions.
Thanks, Dmytro
I think it can be dismissed with dismiss() onInAppPurchaseCompletion action handler but I have no reason to handle it, and if it's not handled it will show error alerts for you (see documentation).
How can I dismiss it and still benefit from default onInAppPurchaseCompletion action?
Thanks,
Hi! I'm seeing some weird animation issues building the Food Truck sample application.^1 I'm running from macOS 15.4 and Xcode 16.3. I'm building the Food Truck application for macOS. I'm not focusing on iOS for now.
The FoodTruckModel adds new Order values with an animation:
// FoodTruckModel.swift
withAnimation(.spring(response: 0.4, dampingFraction: 1)) {
self.orders.append(orderGenerator.generateOrder(number: orders.count + 1, date: .now, generator: &generator))
}
This then animates the OrdersTable when new Order values are added.
Here is a small change to OrdersTable:
// OrdersTable.swift
- @State private var sortOrder = [KeyPathComparator(\Order.status, order: .reverse)]
+ @State private var sortOrder = [KeyPathComparator(\Order.creationDate, order: .reverse)]
Running the app now inserts new Order values at the top.
The problem is I seem to be seeing some weird animation issues here. It seems that as soon as the new Order comes in there is some kind of weird glitch where it appears as if part the animation is coming from the side instead of down from the top:
What's then more weird is that if I seem to affect the state of the Table in any way then the next Order comes in with perfect animation.
Scrolling the Table fixes the animation.
Changing the creationData sort order from reverse to forward and back to reverse fixes the animation.
Any ideas? Is there something about how the Food Truck product is built that would cause this to happen? Is this an underlying issue in the SwiftUI infra?
I had a problem with my app (or in my setup) and searching the web I found a very simple code where part of my problem occurs.
I create a new Multiplatform App and
paste this code in ContentView.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationStack {
VStack {
Text("Navigation article")
.font(.title)
.padding()
NavigationLink("Go to the second view", destination: SecondView())
.padding()
}
.navigationTitle("First View")
}
}
}
struct SecondView: View {
var body: some View {
Text("This is the Second view")
.font(.headline)
.padding()
.navigationTitle("Second View")
}
}
run on iPhone/ iOS no problem
run on a Mac/macOS
Going from view 1 to view 2 work, the back arrow on view 2 is there, and it is working but the second time I go to the view 2, the back arrow is gone.
after looking closely I can see the Arrow Underneath the S of SecondView.
I have tried many things and could not make it work.
I post this in a HackingWithSwift forum and somebody tried the code and said it work. so it seems the problem could be related to my setup but I create another user in my computer , same problem and tried it on my another computer, same problem.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Goal : Drag a sphere across the room and track it's position
Problem: The gesture seems to have no effect on the sphere ModelEntity.
I don't know how to properly attach the gesture to the ModelEntity. Any help is great. Thank you
import SwiftUI
import Foundation
import UIKit
@main
struct testApp: App {
@State var immersionStyle:ImmersionStyle = .mixed
var body: some Scene {
ImmersiveSpace {
ContentView()
}
.immersionStyle(selection: $immersionStyle, in: .mixed, .full, .progressive)
}
}
struct ContentView: View {
@State private var lastPosition: SIMD3? = nil
@State var subscription: EventSubscription?
@State private var isDragging: Bool = false
var sphere: ModelEntity {
let mesh = MeshResource.generateSphere(radius: 0.05)
let material = SimpleMaterial(color: .blue, isMetallic: false)
let entity = ModelEntity(mesh: mesh, materials: [material])
entity.generateCollisionShapes(recursive: true)
return entity
}
var drag: some Gesture {
DragGesture()
.onChanged { _ in self.isDragging = true }
.onEnded { _ in self.isDragging = false }
}
var body: some View {
RealityView { content in
//1. Anchor Entity
let anchor = AnchorEntity(world: SIMD3<Float>(0, 0, -1))
let ball = sphere
//2. add anchor to sphere
anchor.addChild(ball)
content.add(anchor)
subscription = content.subscribe(to: SceneEvents.Update.self) { event in
let currentPosition = ball.position(relativeTo: nil)
if let last = lastPosition, last != currentPosition {
print("Sphere moved from \(last) to \(currentPosition)")
}
lastPosition = currentPosition
}
}
.gesture(drag)
}
}
I was doing an app which had several "camera" buttons each one dedicated to taking/storing/reviewing/deleting an image associated with a variable URL but what should have been a simple no brainer turned out to be a programming nightmare.
To cut a long story short there is a bug in the sheet handling wherebye even tho you have separate instance for each button the camera/picker cylcles sequentially thru the stack of instances for any action finally always placing the image in the first URL. Working with myself debugging, all major AIs (Grok, Claude, Gemini and Perplexity) after 4 x 12hr+ days we finally managed to crack a solution. What follows is Groks interpretation (note it misses the earlier problem of instance cycling!!) ...
You can follow the discussion here: https://x.com/i/grok/share/KHeaUPladURmbFq5qy9W506er
but be warned its long a detailed but if you are having problems then read ...
**Bug Report: Race Conditions with UIImagePickerController in SwiftUI Sheet
**
Environment:
SwiftUI, iOS 17.7.5
Device: iPad Pro (12.9-inch, 2nd generation)
Xcode Version: [Insert your Xcode version]
Date: March 30, 2025
**Issue 1: Multiple Instances of UIImagePickerController Spawned After Dismissal
**
Description:
When using a UIImagePickerController wrapped in a UIViewControllerRepresentable and presented via a SwiftUI .sheet, selecting "Use Photo" resulted in multiple unintended instances of the picker being initialized and presented. The console logs showed repeated "Camera initialized" and "Camera sheet appeared" messages (e.g., multiple <UIImagePickerController: 0x...> instances) after the initial dismissal, despite the sheet being dismissed programmatically.
Reproduction Steps:
Create a SwiftUI view with a button that sets a @State variable showCamera to true.
Present a UIImagePickerController via .sheet(isPresented: $showCamera).
Update a @Binding variable (e.g., photoLocation: URL?) in imagePickerController(_:didFinishPickingMediaWithInfo:) after saving the image.
Dismiss the picker with picker.dismiss(animated: true) and presentationMode.wrappedValue.dismiss().
Observe that updating the @Binding variable triggers a view re-render, causing the .sheet to re-present multiple times before finally staying dismissed.
Root Cause:
A race condition occurred between the view update (triggered by changing photoLocation) and the dismissal of the picker. During the re-render, showCamera remained true momentarily, causing the .sheet modifier to re-evaluate and spawn new picker instances before the onDismiss closure could reset showCamera to false.
The fix involved delaying the @Binding update (photoLocation) until after the picker and sheet were fully dismissed, ensuring showCamera was reset to false before the view re-rendered:
Introduced an onPhotoPicked: (URL) -> Void closure to decouple the photoLocation update from the dismissal timing.
Modified the coordinator to call onPhotoPicked and reset showCamera before initiating dismissal:swift
Issue 2: Single Unintended Picker Reopen After Initial Fix
Description:
After addressing the multiple-instance issue, a single unintended reopen of the picker persisted. The logs showed one additional "Camera initialized" and "Camera sheet appeared" after "Use Photo," before the final dismissal.
Reproduction Steps:
Reproduction Steps:
Use the initial fix with onPhotoPicked and delayed photoLocation update.
Take a photo and select "Use Photo."
Observe one extra picker instance appearing briefly before dismissal completes.
Root Cause:
The @Binding update (photoLocation) was still occurring too early in the dismissal sequence. Although delayed until after picker.dismiss, the view re-render happened while showCamera was still true during the dismissal animation, causing the .sheet to re-present once before onDismiss reset showCamera.
Resolution:
The fix ensured showCamera was set to false before the picker dismissal animation began, preventing the .sheet from re-evaluating during the transition:
Moved the dismissCamera() call (which sets showCamera to false) into the onPhotoPicked callback, executed before picker.dismiss:
CameraView(
photoLocation: $photoLocation,
storeDirectory: storeDirectory,
onPhotoPicked: { url in
print("Photo picked callback for \(id), setting photoLocation: \(url)")
self.photoLocation = url
self.cameraState.dismissCamera() // Sets showCamera to false first
}
)
Kept the dismissal sequence in the coordinator:
DispatchQueue.main.async {
self.parent.onPhotoPicked(fileURL)
picker.dismiss(animated: true) {
self.parent.presentationMode.wrappedValue.dismiss()
}
}
This synchronized the state change with the dismissal, ensuring showCamera was false before the view re-rendered, eliminating the single reopen.
Request:
Could the SwiftUI team clarify if this behavior is expected, or consider improving the .sheet modifier to better handle state transitions during UIKit controller dismissal? A more robust bridge between SwiftUI’s declarative state and UIKit’s imperative lifecycle could prevent such race conditions.
I am developing an application which make use of 2 ornaments anchored to a volumetric window, one used a toolbar and one to display different views.
The problem I am facing consistently is that the ornaments seems to scale up or down after moving the volume using the OS handle or starting a GroupActivity session.
This first image shows the ornaments as soon as I started the app, no dragging nor group activities:
This second images shows them as soon as I join a group activity session:
The map, which might seem smaller, has not been touched and has always the same scale.
In this last image I had just dragged the entire volume using the OS toolbar, resulting in the ornaments scaling down:
This is how the volume and the ornaments are declared:
WindowGroup(id: "CityVolume") {
let cityVM = CityViewModel(volumeSize: CityView.initialVolumeSize)
CityView(cityVM: cityVM)
.ornament(attachmentAnchor: .scene(.bottomFront)) {
HStack {
TourismChartsButton()
LandmarksListButton()
CenterMapButton()
ToggleImmersiveSpaceButton()
TrafficDataButton()
BusLinesButton()
}
.padding()
.offset(z: 10)
.rotation3DEffect(Angle(degrees: 15), axis: (x: 1.0, y: 0.0, z: 0.0))
}
.ornament(attachmentAnchor: .scene(.back)) {
ZStack {
if AppModel.Instance.tourismVM.isChartViewVisible {
TourismChartsView()
}
if AppModel.Instance.busLinesVM.isDataViewEnabled {
BusLineView()
}
}
}
.task(observeGroupActivity)
.onAppear {
appModel.cityVM = cityVM
}
}
.windowStyle(.volumetric)
.windowResizability(.contentSize)
.volumeWorldAlignment(.gravityAligned)
.defaultSize(CityView.initialVolumeSize, in: .meters)
It happens also without starting a SharePlay session, but not as frequently as during SharePlay. Experienced the same behaviour with toolbars.
Am I doing something wrong with how I created the ornaments? Am I missing something?