Construct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.

Posts under UIKit tag

200 Posts

Post

Replies

Boosts

Views

Activity

UITabBar (Liquid Glass) rendering breaks when UITabBarController is recreated while fully obscured by a fullscreen modal
I’m seeing a rendering issue with UITabBarController on iOS 26 (Liquid Glass), and I’d like to confirm whether others can reproduce this or have a workaround. Summary If a UITabBarController is recreated while it is fully hidden behind a fullscreen modal, the tab bar renders incorrectly after dismissal. Selected tab becomes nearly invisible Unselected tabs appear to show both selected and unselected tint colors Looks like multiple rendering states are composited incorrectly This only happens with: iOS 26 (Liquid Glass enabled) UIKit UITabBarController It does not reproduce with SwiftUI TabView. Minimal Reproduction Code This is a complete, minimal example: import UIKit // MARK: - Root class RootViewController: UIViewController { private var tabBar: UITabBarController? private var modalPresented = false override func viewDidLoad() { super.viewDidLoad() installTabBar() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // Present once on first appear, simulating an app-launch login flow. if !modalPresented { modalPresented = true presentModal() } } private func installTabBar() { let tab = UITabBarController() tab.viewControllers = [ makeTab(title: "Tab 1", systemImage: "1.circle"), makeTab(title: "Tab 2", systemImage: "2.circle"), ] tabBar = tab addChild(tab) view.addSubview(tab.view) tab.view.frame = view.bounds tab.didMove(toParent: self) } private func makeTab(title: String, systemImage: String) -> UIViewController { let vc = UIViewController() vc.view.backgroundColor = .systemBackground vc.tabBarItem = UITabBarItem(title: title, image: UIImage(systemName: systemImage), tag: 0) return vc } private func presentModal() { let modal = ModalViewController() modal.onDismiss = { [weak self] in // Recreate the tab bar while it is still fully hidden by the modal. // This seems to trigger incorrect Liquid Glass rendering. self?.tabBar?.willMove(toParent: nil) self?.tabBar?.view.removeFromSuperview() self?.tabBar?.removeFromParent() self?.installTabBar() // ← created while invisible self?.dismiss(animated: true) } modal.modalPresentationStyle = .fullScreen present(modal, animated: true) } } // MARK: - Modal class ModalViewController: UIViewController { var onDismiss: (() -> Void)? override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground let button = UIButton(type: .system) button.setTitle("Dismiss", for: .normal) button.titleLabel?.font = .preferredFont(forTextStyle: .title2) button.addTarget(self, action: #selector(dismissTapped), for: .touchUpInside) button.translatesAutoresizingMaskIntoConstraints = false view.addSubview(button) NSLayoutConstraint.activate([ button.centerXAnchor.constraint(equalTo: view.centerXAnchor), button.centerYAnchor.constraint(equalTo: view.centerYAnchor), ]) } @objc private func dismissTapped() { onDismiss?() } } Expected Behavior The tab bar renders normally with correct Liquid Glass appearance: Selected tab is clearly visible Unselected tabs show only inactive tint Actual Behavior Selected tab becomes nearly invisible Unselected tabs show a mix of selected + unselected tint The issue resolves after backgrounding and returning to foreground Observations / Workarounds The issue does not reproduce if: The tab bar is recreated after dismissal: self.dismiss(animated: true) { self.installTabBar() } Using SwiftUI TabView Using a presentation style that does not fully cover the screen (.pageSheet, etc.) Question Has anyone else encountered this? Is there a recommended workaround besides delaying creation until after dismissal? It seems like Liquid Glass rendering may not initialize correctly when the view is attached while fully obscured, but I’m not sure if this is expected behavior or a bug.
1
0
148
3w
How to add Paste button in UIMenu such that the system "allow app to paste" prompt does not appear
Apps that try to access the contents of the pasteboard cause a system prompt to appear asking the user "AppName" would like to paste from "OtherAppName" Do you want to allow this? Don't Allow Paste Allow Paste This prompt does not appear if you implement a UIPasteControl and the user taps it to signal intent to paste, but this control cannot be placed into a UIMenu. I read this could be achieved with UIAction.Identifiers like .paste or .newFromPasteboard but the prompt still appears with the following code. What's the trick? override func viewDidLoad() { super.viewDidLoad() title = "TestPaste" view.backgroundColor = .systemBackground let imageView = UIImageView() imageView.translatesAutoresizingMaskIntoConstraints = false imageView.contentMode = .scaleAspectFit imageView.clipsToBounds = true view.addSubview(imageView) NSLayoutConstraint.activate([ imageView.topAnchor.constraint(equalTo: view.topAnchor), imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor), imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor), imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add", image: UIImage(systemName: "plus"), menu: UIMenu(children: [ UIAction(identifier: .paste) { _ in imageView.image = UIPasteboard.general.image } ])) }
4
0
520
3w
Embedded Collection View in SwiftUI offset issue
I have a collection view that covers all the screen and it is scrolling behavior is paging. This collection view is embedded in a UIViewRepresentable and used in a SwiftUI app. The issue is that when users rotate the devices, sometimes the CollectionView.contentOffset get miscalculated and shows 2 pages. This is the code that I'm using for the collectionView and collectionViewLayout: class PageFlowLayout: UICollectionViewFlowLayout { override class var layoutAttributesClass: AnyClass { UICollectionViewLayoutAttributes.self } private var calculatedAttributes: [UICollectionViewLayoutAttributes] = [] private var calculatedContentWidth: CGFloat = 0 private var calculatedContentHeight: CGFloat = 0 public weak var delegate: PageFlowLayoutDelegate? override var collectionViewContentSize: CGSize { return CGSize(width: self.calculatedContentWidth, height: self.calculatedContentHeight) } override init() { super.init() self.estimatedItemSize = .zero self.scrollDirection = .horizontal self.minimumLineSpacing = 0 self.minimumInteritemSpacing = 0 self.sectionInset = .zero } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func prepare() { guard let collectionView = collectionView, collectionView.numberOfSections > 0, calculatedAttributes.isEmpty else { return } estimatedItemSize = collectionView.bounds.size for item in 0..<collectionView.numberOfItems(inSection: 0) { let indexPath = IndexPath(item: item, section: 0) let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath) let itemOrigin = CGPoint(x: CGFloat(item) * collectionView.frame.width, y: 0) attributes.frame = .init(origin: itemOrigin, size: collectionView.frame.size) calculatedAttributes.append(attributes) } calculatedContentWidth = collectionView.bounds.width * CGFloat(calculatedAttributes.count) calculatedContentHeight = collectionView.bounds.size.height } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { return calculatedAttributes.compactMap { return $0.frame.intersects(rect) ? $0 : nil } } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { return calculatedAttributes[indexPath.item] } override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { guard let collectionView else { return false } if newBounds.size != collectionView.bounds.size { return true } if newBounds.size.width > 0 { let pages = calculatedContentWidth / newBounds.size.width // If the contentWidth matches the number of pages, // if not it requires to layout the cells let arePagesExact = pages.truncatingRemainder(dividingBy: 1) == 0 return !arePagesExact } return false } override func invalidateLayout() { calculatedAttributes = [] super.invalidateLayout() } override func shouldInvalidateLayout(forPreferredLayoutAttributes preferredAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> Bool { guard let collectionView, #available(iOS 18.0, *) else { return false } return preferredAttributes.size != collectionView.bounds.size } override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext) { guard let customContext = context as? UICollectionViewFlowLayoutInvalidationContext else { return } if let collectionView, let currentPage = delegate?.currentPage() { let delta = (CGFloat(currentPage) * collectionView.bounds.width) - collectionView.contentOffset.x customContext.contentOffsetAdjustment.x += delta } calculatedAttributes = [] super.invalidateLayout(with: customContext) } override func prepare(forAnimatedBoundsChange oldBounds: CGRect) { super.prepare(forAnimatedBoundsChange: oldBounds) guard let collectionView else { return } if oldBounds.width != collectionView.bounds.width { invalidateLayout() } } override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint { guard let collectionView, let currentPage = delegate?.currentPage() else { return .zero } let targetContentOffset = super.targetContentOffset(forProposedContentOffset: proposedContentOffset) let targetPage = targetContentOffset.x / collectionView.frame.width if targetPage != CGFloat(currentPage) { let xPosition = CGFloat(currentPage) * collectionView.frame.width return CGPoint(x: xPosition, y: 0) } return targetContentOffset } // This function updates the contentOffset in case is wrong override func finalizeCollectionViewUpdates() { guard let collectionView, let currentPage = delegate?.currentPage() else { return } let xPosition = CGFloat(currentPage) * collectionView.bounds.width if xPosition != collectionView.contentOffset.x { let offset = CGPoint(x: xPosition, y: 0) collectionView.setContentOffset(offset, animated: false) } } } The full implementation is attached in the .txt file: RotationTestView.txt
6
0
238
Apr ’26
iOS 26 UITabBar Layout Glitch: Custom Appearance vs. Liquid Glass Effects during Rotation
Hello, I am encountering a UI layout issue on iOS 26 where UITabBar items become squashed or overlapping during device rotation (from Portrait to Landscape). This glitch occurs specifically when a custom UITabBarAppearance is applied. 1. "Liquid Glass" and UITabBar Customization According to TN3106, Apple states: "Starting in iOS 26, reduce your use of custom backgrounds in navigation elements and controls. While the techniques in this document remain valid for iOS 18 and earlier, prefer to remove custom effects and let the system determine the navigation bar background appearance. Any custom backgrounds and appearances you use in the navigation bar might overlay or interfere with Liquid Glass or other effects that the system provides, such as the scroll edge effect." Does this guidance also apply to UITabBar? Specifically, could setting a custom background color via UITabBarAppearance interfere with internal layout constraints required for the Liquid Glass effect to adapt correctly during orientation changes? It appears that the internal UIStackView may fail to recalculate width in time when these system effects are active. 2. Validation of the Layout Workaround To maintain our app's visual identity while resolving this squashing issue, I implemented the following fix within the transition coordinator of my UITabBarController: Code Implementation (Objective-C) [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { // Forcing a layout refresh to synchronize with the rotation animation [weakSelf.tabBar invalidateIntrinsicContentSize]; [weakSelf.tabBar setNeedsLayout]; [weakSelf.tabBar layoutIfNeeded]; } completion:nil]; Is manually invalidating the intrinsic content size an acceptable practice for iOS 26? Or is there a more "system-native" approach to ensure UITabBar layout remains stable and compatible with Liquid Glass, especially when custom appearances are necessary?
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
358
Apr ’26
iOS 26: Interactive sheet dismissal causes layout hitch in underlying SwiftUI view
I’ve been investigating a noticeable animation hitch when interactively dismissing a sheet over a SwiftUI screen with moderate complexity. This was not the case on iOS 18, so I’m curious if others are seeing the same on iOS 26 or have found any mitigations. When dismissing a sheet via the swipe gesture, there’s a visible hitch right after lift-off. The hitch comes from layout work in the underlying view (behind the sheet) The duration scales with the complexity of that view (e.g. number of TextFields/layout nodes) The animation for programmatic dismiss (e.g. tapping a “Done” button) is smooth, although it hangs for a similar amount of time before dismissing, so it appears that the underlying work still happens. SwiftUI is not reevaluating the body during this (validated with Self._printChanges()), so that is not the cause. Using Instruments, the hitch shows up as a layout spike on the main thread: 54ms UIView layoutSublayersOfLayer 54ms └─ _UIHostingView.layoutSubviews 38ms └─ SwiftUI.ViewGraph.updateOutputs 11ms ├─ partial apply for implicit closure #1 in closure #1 │ in closure #1 in Attribute.init<A>(_:) 4ms └─ -[UIView For the same hierarchy with varying complexity: ~3 TextFields in a List: ~25ms (not noticeable) ~20+ TextFields: ~60ms (clearly visible hitch) The same view hierarchy on iOS 18 did not exhibit a visible hitch. I’ve tested this on an iOS 26.4 device and simulator. I’ve also included a minimum reproducible example that illustrates this: struct ContentView: View { @State var showSheet = false var body: some View { NavigationStack { ScrollView { ForEach(0..<120) { _ in RowView() } } .navigationTitle("Repro") .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Present") { showSheet = true } } } .sheet(isPresented: $showSheet) { PresentedSheet() } } } } struct RowView: View { @State var first = "" @State var second = "" var body: some View { VStack(alignment: .leading, spacing: 12) { Text("Row") .font(.headline) HStack(spacing: 12) { TextField("First", text: $first) .textFieldStyle(.roundedBorder) TextField("Second", text: $second) .textFieldStyle(.roundedBorder) } HStack(spacing: 12) { Text("Third") Text("Fourth") Image(systemName: "chevron.right") } } } } struct PresentedSheet: View { @Environment(\.dismiss) private var dismiss var body: some View { NavigationStack { List {} .navigationTitle("Swipe To Dismiss Me") .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Done") { dismiss() } } } } } } Is anyone else experiencing this and have any mitigations been found beyond reducing view complexity? I’ve filed a feedback report under FB22501630.
1
0
266
Apr ’26
EXC_BAD_ACCESS in drawHierarchy(in:afterScreenUpdates:) on iOS 26.3.1+ — IOSurface CIF10 decompression crash
We're experiencing an EXC_BAD_ACCESS (SIGSEGV) crash in UIView.drawHierarchy(in:afterScreenUpdates: false) that occurs only on iOS 26.3.1 and later. It does not reproduce on iOS 26.3.0 or earlier. Crash Stack Thread 0 (Main Thread) — EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0 libvDSP.dylib vConvert_XRGB2101010ToARGB8888_vec 1 ImageIO IIOIOSurfaceWrapper_CIF10::CopyImageBlockSetWithOptions 2 ImageIO IIOImageProviderInfo::CopyImageBlockSetWithOptions 3 ImageIO CGImageReadGetBytesAtOffset 4 CoreGraphics CGAccessSessionGetBytes 5 CoreGraphics img_data_lock 6 CoreGraphics CGSImageDataLock 7 CoreGraphics ripc_AcquireImage 8 CoreGraphics ripc_DrawImage 9 CoreGraphics CGContextDrawImage 10 UIKitCore -[UIView(Rendering) drawHierarchy:afterScreenUpdates:] The crash occurs during 10-bit CIF10 → 8-bit ARGB8888 pixel conversion when the IOSurface backing a UIImageView in the view hierarchy is deallocated mid-render. How to Reproduce Display a scrollable list with multiple UIImageViews loaded via an async image library Call drawHierarchy(in: bounds, afterScreenUpdates: false) on visible cells periodically Scroll to trigger image recycling Crash occurs sporadically — more likely under memory pressure or rapid image recycling What We've Tried Both UIKit off-screen rendering approaches crash on iOS 26.3.1: Approach Result drawHierarchy(afterScreenUpdates: false) EXC_BAD_ACCESS in CIF10 IOSurface decompression view.layer.render(in:) EXC_BAD_ACCESS in Metal (agxaAssertBufferIsValid) iOS Version Correlation iOS 26.3.0 and earlier: No crash iOS 26.3.1 (23D8133)+: Crash occurs (~5 events per 7 days) We suspect the ImageIO security patches in iOS 26.3 (CVE-2026-20675, CVE-2026-20634) may have changed IOSurface lifecycle timing, exposing a race condition between drawHierarchy's composited buffer read and asynchronous IOSurface reclamation by the OS. Crash Data We sampled 3 crash events: Event 1 (iOS 26.3.1): 71 MB free memory — memory pressure Event 2 (iOS 26.3.1): 88 MB free memory — memory pressure Event 3 (iOS 26.3.2): 768 MB free memory — NOT memory pressure Event 3 shows this isn't purely a low-memory issue. The IOSurface can be reclaimed even with ample free memory, likely due to async image recycling. Question Is this a known regression in iOS 26.3.1? Is there a safe way to snapshot a view hierarchy containing IOSurface-backed images without risking EXC_BAD_ACCESS? Should drawHierarchy gracefully handle the case where an IOSurface backing store is reclaimed during the render? Any guidance or workarounds would be appreciated. We've also filed this as Feedback (will update with FB number after submission).
2
0
377
Apr ’26
Keyboard greyed issue
I am facing weird keyboard issue when building the app with Xcode 26 recently. Actual behaviour I need is: But one below is the issue as the keyboard keys are greyed out: Please tell how to resolve this issue
4
0
325
Apr ’26
Navigation bar flickers when pushing to a different screen
Hi everyone, I’m building a SwiftUI app using NavigationStack and running into a weird nav bar issue. For the setup I have a 'home' screen with a vertical ScrollView and a large edge-to-edge header that extends under the top safe area (using .ignoresSafeArea(edges: .top)). I also have a 'detail' screen with a similar immersive layout, where the header/poster image sits at the top and the ScrollView also extends under the top area. I’m using the native navigation bar on both screens and default back button, not a custom nav bar, and I’m not manually configuring UINavigationBarAppearance, I'm just relying on SwiftUI’s default/automatic toolbar behavior. The problem I’m facing is when I push from home to the detail screen, the top nav area briefly flickers and shows the system navigation bar/material background (white in light mode, black in dark mode). It’s clearly the system material, not the poster/image underneath. The screen initially renders with that nav bar state (white/dark), and only after I start scrolling does it correct itself and visually align with the header/background behind it. What I'm thinking is that maybe the detail screen initially renders with systemBackground, so the nav bar uses its default (standard) appearance on the first frame, and only after layout/interaction, once the image-derived background settles, does it switch to the correct scroll-edge/transparent style. One important thing, if I hide the nav bar on the detail screen using .toolbar(.hidden, for: .navigationBar), the issue disappears completely. So this seems specifically tied to the native nav bar’s initial render/appearance timing during the push, rather than just the layout or image loading. I’d prefer to keep the native nav bar and back button rather than implement a custom approach. Has anyone faced this issue before, or is there a correct way to structure edge-to-edge content under the nav bar so it renders properly on first push? Video of the issue: https://imgur.com/a/OYHtYbp NavigationStack { ScrollView { HeroView() } .ignoresSafeArea(edges: .top) .navigationTitle("Cinema") .toolbarTitleDisplayMode(.inlineLarge) .toolbarBackgroundVisibility(.automatic, for: .navigationBar) .navigationDestination(for: Route.self) { route in DetailView(movie: route.movie) } } var body: some View { ScrollView { HeaderPosterView() } .ignoresSafeArea(edges: .top) .navigationBarTitleDisplayMode(.inline) .toolbarBackgroundVisibility(.automatic, for: .navigationBar) } }
0
1
225
Apr ’26
DiffableDataSource hangs on apply
About a year ago, I developed and released an app on the App Store (I believe it was running on the Sequoia SDK at the time), and everything was working fine. I’m now revisiting the project using the newer Tahoe SDK, and I’m running into an issue with DiffableDataSource. Specifically, the app hangs and CPU usage spikes to 100% when applying snapshots. Has anyone experienced similar issues after upgrading to newer SDKs? Are there any recent changes or pitfalls with DiffableDataSource (e.g., threading, Hashable requirements, or snapshot handling) that I should be aware of? Any insights or suggestions would be greatly appreciated. extension Section { enum Identifier: Int, CaseIterable { case main } enum Item: Hashable { case file(FileViewData) } } struct FileViewData: Equatable, Hashable, Identifiable { let id: String let name: String var accessoryViewData: KTFDownloadAccessoryViewData init( id: String, name: String, accessoryViewData: KTFDownloadAccessoryViewData = .nothing ) { self.id = id self.name = name self.accessoryViewData = accessoryViewData } } public enum KTFDownloadAccessoryViewData: Equatable, Hashable { case nothing case selected(SelectedState) case completed public enum SelectedState: Equatable, Hashable { case nothing case waiting case downloading(Double) } } When I changed FileViewData as below, no hangs but item appearance doesn't change of course. struct FileViewData: Equatable, Hashable, Identifiable { let id: String let name: String var accessoryViewData: KTFDownloadAccessoryViewData init( id: String, name: String, accessoryViewData: KTFDownloadAccessoryViewData = .nothing ) { self.id = id self.name = name self.accessoryViewData = accessoryViewData } func hash(into hasher: inout Hasher) { hasher.combine(id) } static func == (lhs: FileViewData, rhs: FileViewData) -> Bool { return lhs.id == rhs.id } }
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
150
Apr ’26
Potentially Unfair Limitation for Third-Party Keyboard Developers
When developing a custom keyboard on iOS, even after enabling Full Access (RequestsOpenAccess = true), it is still not possible to record audio — the recording simply does not start. This is despite the fact that: the user is explicitly warned the user provides informed consent by enabling Full Access According to Apple’s documentation: https://developer.apple.com/documentation/uikit/configuring-open-access-for-a-custom-keyboard “However, with RequestsOpenAccess set to true, the keyboard has all the capabilities in the preceding list.” At the same time, the preceding list includes: “No access to microphone and speaker” This creates ambiguity. The wording suggests that enabling Full Access should lift prior restrictions, yet in practice, microphone access remains unavailable to third-party keyboards. Why this is concerning With Full Access enabled, a keyboard already has: network access the ability to transmit user input From a privacy standpoint, this is already highly sensitive. Preventing microphone access while allowing these capabilities appears inconsistent. Meanwhile, Apple’s own system keyboard supports voice dictation, which creates a functional gap between first-party and third-party keyboards. Competition perspective This raises a broader question about equal access to platform capabilities. Restricting third-party keyboards from using the microphone — while first-party solutions can — may be seen as: unequal treatment of developers a limitation of competition in input methods Such differences are increasingly scrutinized under EU regulations like the Digital Markets Act and Article 102 TFEU, which emphasize fair access to platform features and prohibit self-preferencing by dominant platforms. Request for clarification Is microphone access intentionally restricted for all third-party keyboards, even with Full Access enabled? If so, what is the technical or policy justification? Are there plans to provide a secure and user-consented way to enable audio input for custom keyboards? Clarification on this would help developers better understand platform limitations and design decisions.
0
0
245
Apr ’26
UITextView cursor sometimes jumps up when pressing arrow down key and setting typingAttributes
My app uses TextKit 1 and unfortunately still cannot migrate to TextKit 2 because of some bugs (for instance in FB17103305 I show how NSTextView.shouldDrawInsertionPoint has no effect, but I opened that feedback exactly one year ago and it still has no answer). Unfortunately TextKit 1 has another bug which causes the text cursor to jump unpredictably up or down when pressing the arrow keys and setting UITextView.typingAttributes. Run the code below on iPhone 17 Pro Max Simulator. Scroll the text down until you see “Header 2”. Place the text cursor after “# “. Press the arrow down key twice to move the cursor two lines down. The cursor moves to the top of the view instead. Continuing to press the arrow keys up and down results in the cursor sometimes moving as expected, other times jumping around wildly. Does anyone know a workaround? I created FB22382453. class TextView: UITextView, UITextViewDelegate { override func awakeFromNib() { let _ = layoutManager delegate = self let header = textAttributes(fontSize: 30) let body = textAttributes(fontSize: 15) let string = NSMutableAttributedString(string: String(repeating: "a", count: 2681) + "\n", attributes: body) string.append(NSAttributedString(string: """ # Header 1 """, attributes: header)) string.append(NSMutableAttributedString(string: String(repeating: "a", count: 5198) + "\n", attributes: body)) string.append(NSAttributedString(string: """ # Header 2 """, attributes: header)) string.append(NSMutableAttributedString(string: String(repeating: "a", count: 7048) + "\n", attributes: body)) textStorage.setAttributedString(string) } func textViewDidChangeSelection(_ textView: UITextView) { typingAttributes = textStorage.attributes(at: selectedRange.location - 1, effectiveRange: nil) } private func textAttributes(fontSize: Double) -> [NSAttributedString.Key: Any] { var textAttributes = [NSAttributedString.Key: Any]() textAttributes[.font] = UIFont(name: "Courier", size: fontSize) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.minimumLineHeight = round(fontSize * 1.3) paragraphStyle.maximumLineHeight = paragraphStyle.minimumLineHeight textAttributes[.paragraphStyle] = paragraphStyle return textAttributes } }
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
154
Mar ’26
Left-flick and right-flick gestures with VoiceOver and UIAccessibilityReadingContent
Hi, I have an app that displays lines of text, that I want to make accessible with VoiceOver. It's based on a UITextView. I have implemented the UIAccessibilityReadingContent protocol, following the instructions in https://developer.apple.com/videos/play/wwdc2019/248 and now users can see the screen line by line, by moving their fingers on the screen. That works fine. However, users would also like to be able to use left-flick and right-flick to move to the previous or next line on the screen, and I haven't been able to make this work. I can see that left-flick triggers accessibilityPreviousTextNavigationElement and right-flick triggers accessibilityNextTextNavigationElement, but I don't understand what these variables should be.
1
0
1.5k
Apr ’26
Scene resizing on iPad breaks UIPageViewController's setViewControllers
The following is verbatim of a feedback report (FB22367951) I submitted, shared here as someone else might be interested to see it. I have reproduced this bug on iPadOS 26.3.1 (a) and 26.4. During scene resizing on iPad, UIPageViewController's setViewControllers method fails to do its work. The navigation starts and for a brief moment you can see the new view controller coming from the expected direction, but shortly after it fails and stays on the same [current] view controller. It doesn't even call the completion handler when it fails. When the navigation succeeds (due to not resizing a scene during the navigation) after previously failing at least once, the completion handler is sometimes called more than once. I have created a demo project, which I have pushed to this repo: https://github.com/galijot/SceneResize-Breaks-UIPageViewController I have also attached a zip of the project to this report.
0
0
262
Mar ’26
Left navigation bar items become invisible after rotating device and presenting detail view in split view
A user of my app, whose main view is a split view, reported an issue which causes the left navigation bar items to disappear without apparent reason if they rotate the device and later show the detail view, preventing them from using the back button to show the root view again. Am I doing something wrong or is it a bug? I can reproduce the issue with the following steps: Create a new document-based iOS app (as it uses scenes by default, as opposed to a regular app). Paste the code below. In the target build settings, delete "Launch Screen Interface File Base Name" and set "Launch Screen (Generation)" to YES. Without this step, for some reason, the issue doesn't happen. Launch the app in iPhone Simulator. Tap the top left button to show the root view, then the “detail” button to show the detail view. The left navigation bar button is still visible. Rotate the Simulator window right, then left again. Tap the top left button to show the root view, then the “detail” button to show the detail view. Now the left navigation bar button is invisible. Rotating the device right and left again solves the issue. I filed FB22363118. class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { window = UIWindow(windowScene: scene as! UIWindowScene) let split = SplitViewController() window!.rootViewController = split window!.makeKeyAndVisible() split.showDetail() } } class SplitViewController: UISplitViewController, UISplitViewControllerDelegate { var detailNavigationViewController: UINavigationController! init() { super.init(nibName: nil, bundle: nil) detailNavigationViewController = UINavigationController(rootViewController: DetailViewController()) viewControllers = [UINavigationController(rootViewController: RootViewController())] } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func showDetail() { showDetailViewController(detailNavigationViewController, sender: nil) } func showRoot() { (viewControllers.first as? UINavigationController)?.popViewController(animated: true) } } class RootViewController: UIViewController { override func loadView() { navigationItem.title = "root" let button = UIButton(primaryAction: UIAction(handler: { [self] _ in (splitViewController as! SplitViewController).showDetail() })) button.setTitle("detail", for: .normal) view = button } } class DetailViewController: UIViewController { override func loadView() { navigationItem.title = "detail" view = UIView() registerForTraitChanges([UITraitHorizontalSizeClass.self]) { (self: Self, previousTraitCollection) in if previousTraitCollection.horizontalSizeClass != self.traitCollection.horizontalSizeClass { self.updateBarButtons() } } updateBarButtons() } private func updateBarButtons() { navigationItem.leftBarButtonItem = UIBarButtonItem(primaryAction: UIAction(image: UIImage(systemName: "sidebar.leading")) { [self] _ in (self.splitViewController as! SplitViewController).showRoot() }) navigationItem.rightBarButtonItem = UIBarButtonItem(title: "right") } }
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
98
Mar ’26
IOS Swift touch screen issue
MyOwnKeyboard Pad app has 4 text views with textfields that use touch screen for editing. There is one view, Compose, that has a textfield and a textview (UIRepresentable). The app enters text into the view using textfield buttons. The app has total control of editing. When entering text if the screen is touched it conflicts the cursor position and creates an "out of bounds" failure. In that view the app does not need any touch events. I need a method in UIRepresentable to disable the touch event. I am not familiar with UIRepresentable as this code was provided by Apple to solve a 16 bit unicode character issue. What would be the code to disable touch events in the UIRepresentable compose view. The app is free for a while until this problem is fixed. It is for iPads 11"+ . The name in the app store is MyOwnKeyboard Pad. I know some great engineer will find the answer. DTS tried. Thanks to all, maybe I'll sell some. Charlie 25mar26
1
0
185
Mar ’26
UISheetPresentationController Disable Liquid Glass For Foreground Elements Within a Sheet
Hello just wondering if there is a supported way to disable the liquid glass effect that is passed down to every subview within a sheet using the medium or smaller detents? There are certain views with information in them within this sheet that I do not want to become semi transparent but I want to keep the background view of the sheet using the default liquid glass effect.
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
210
Mar ’26
iPadOS 26: How to prevent new scene creation when sharing a file to my app?
Many different types of files can be opened in my app. If a user, for example, views a file in the Files app and chooses to share the file, they can select my app from the list of options. My app is then given a chance to handle the file as needed. This works just fine in most cases. However, on iPadOS 26, if the user has set the iPad's Multitasking to either Windowed Apps or Stage Manager, then any time they choose to share a file with my app, a new scene (and window) is created. The user is usually not even aware that more and more windows/scenes are being created. It's only after they long-press on the app icon and select Show All Windows (or look under the Open Windows section) do they see far more windows than expected. Under iPadOS 17, 18, or with 26 set to Full Screen Apps, sharing a file to my app simply uses an existing scene, even if the user has explicitly created multiple scenes. A new scene is never created when sharing a file to my app unless there is no existing scene. Due to the nature of my app, even if the user has setup the iPad with Windowed App or Stage Manager under iPadOS 26, it would be far better if a new scene was not created and an existing scene was used. In other words, have it behave just as it does under iPadOS 17 or 18, or with 26 set as Full Screen Apps. Is there any way to configure an app to always use an existing scene when a file is shared with the app? My app is written with UIKit. Under iPadOS 26 with multitasking set to Windowed Apps or Stage Manager, sharing a file with my app results in the UIApplicationDelegate method application(_:configurationForConnecting:options:) being called. At this point a new scene is already in the process of being created. I don't see anything that can be set in the Info.plist. I do not see any relevant UIApplicationDelegate methods. Am I missing something or is this not possible?
0
0
216
Mar ’26
Layout glitch after rotation when using UIWindowScene sizeRestrictions on iPadOS 26
Hi everyone, I am experiencing a strange rendering issue on iPadOS 26 when sizeRestrictions.minimumSize is set on a UIWindowScene. After rotating the device and then rotating it back to the original orientation, the window appears to be stretched based on its previous dimensions. This resulting "stretched" area does not resize or redraw correctly, leaving a significant black region on the screen. Interestingly, as soon as I interact with the window (e.g., a slight drag or touch), the UI snaps back to its intended state and redraws perfectly. Here is a sample code and capture of behavior. class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } windowScene.sizeRestrictions?.minimumSize = CGSize( width: 390, height: 844 // larger than the height of iPad in landscape ) // initialize... } } Has anyone else encountered this behavior? If so, are there any known workarounds to force a layout refresh or prevent this "ghost" black area during the rotation transition? Any insights would be greatly appreciated. Thanks!
1
0
254
Mar ’26
UITabBar (Liquid Glass) rendering breaks when UITabBarController is recreated while fully obscured by a fullscreen modal
I’m seeing a rendering issue with UITabBarController on iOS 26 (Liquid Glass), and I’d like to confirm whether others can reproduce this or have a workaround. Summary If a UITabBarController is recreated while it is fully hidden behind a fullscreen modal, the tab bar renders incorrectly after dismissal. Selected tab becomes nearly invisible Unselected tabs appear to show both selected and unselected tint colors Looks like multiple rendering states are composited incorrectly This only happens with: iOS 26 (Liquid Glass enabled) UIKit UITabBarController It does not reproduce with SwiftUI TabView. Minimal Reproduction Code This is a complete, minimal example: import UIKit // MARK: - Root class RootViewController: UIViewController { private var tabBar: UITabBarController? private var modalPresented = false override func viewDidLoad() { super.viewDidLoad() installTabBar() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // Present once on first appear, simulating an app-launch login flow. if !modalPresented { modalPresented = true presentModal() } } private func installTabBar() { let tab = UITabBarController() tab.viewControllers = [ makeTab(title: "Tab 1", systemImage: "1.circle"), makeTab(title: "Tab 2", systemImage: "2.circle"), ] tabBar = tab addChild(tab) view.addSubview(tab.view) tab.view.frame = view.bounds tab.didMove(toParent: self) } private func makeTab(title: String, systemImage: String) -> UIViewController { let vc = UIViewController() vc.view.backgroundColor = .systemBackground vc.tabBarItem = UITabBarItem(title: title, image: UIImage(systemName: systemImage), tag: 0) return vc } private func presentModal() { let modal = ModalViewController() modal.onDismiss = { [weak self] in // Recreate the tab bar while it is still fully hidden by the modal. // This seems to trigger incorrect Liquid Glass rendering. self?.tabBar?.willMove(toParent: nil) self?.tabBar?.view.removeFromSuperview() self?.tabBar?.removeFromParent() self?.installTabBar() // ← created while invisible self?.dismiss(animated: true) } modal.modalPresentationStyle = .fullScreen present(modal, animated: true) } } // MARK: - Modal class ModalViewController: UIViewController { var onDismiss: (() -> Void)? override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground let button = UIButton(type: .system) button.setTitle("Dismiss", for: .normal) button.titleLabel?.font = .preferredFont(forTextStyle: .title2) button.addTarget(self, action: #selector(dismissTapped), for: .touchUpInside) button.translatesAutoresizingMaskIntoConstraints = false view.addSubview(button) NSLayoutConstraint.activate([ button.centerXAnchor.constraint(equalTo: view.centerXAnchor), button.centerYAnchor.constraint(equalTo: view.centerYAnchor), ]) } @objc private func dismissTapped() { onDismiss?() } } Expected Behavior The tab bar renders normally with correct Liquid Glass appearance: Selected tab is clearly visible Unselected tabs show only inactive tint Actual Behavior Selected tab becomes nearly invisible Unselected tabs show a mix of selected + unselected tint The issue resolves after backgrounding and returning to foreground Observations / Workarounds The issue does not reproduce if: The tab bar is recreated after dismissal: self.dismiss(animated: true) { self.installTabBar() } Using SwiftUI TabView Using a presentation style that does not fully cover the screen (.pageSheet, etc.) Question Has anyone else encountered this? Is there a recommended workaround besides delaying creation until after dismissal? It seems like Liquid Glass rendering may not initialize correctly when the view is attached while fully obscured, but I’m not sure if this is expected behavior or a bug.
Replies
1
Boosts
0
Views
148
Activity
3w
NSInternalInconsistencyException
Invalid parameter not satisfying: targetNode [UIGestureGraphEdge initWithLabel:sourceNode:targetNode:directed:] How to locate this crash?
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
1
Boosts
0
Views
97
Activity
3w
How to add Paste button in UIMenu such that the system "allow app to paste" prompt does not appear
Apps that try to access the contents of the pasteboard cause a system prompt to appear asking the user "AppName" would like to paste from "OtherAppName" Do you want to allow this? Don't Allow Paste Allow Paste This prompt does not appear if you implement a UIPasteControl and the user taps it to signal intent to paste, but this control cannot be placed into a UIMenu. I read this could be achieved with UIAction.Identifiers like .paste or .newFromPasteboard but the prompt still appears with the following code. What's the trick? override func viewDidLoad() { super.viewDidLoad() title = "TestPaste" view.backgroundColor = .systemBackground let imageView = UIImageView() imageView.translatesAutoresizingMaskIntoConstraints = false imageView.contentMode = .scaleAspectFit imageView.clipsToBounds = true view.addSubview(imageView) NSLayoutConstraint.activate([ imageView.topAnchor.constraint(equalTo: view.topAnchor), imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor), imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor), imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add", image: UIImage(systemName: "plus"), menu: UIMenu(children: [ UIAction(identifier: .paste) { _ in imageView.image = UIPasteboard.general.image } ])) }
Replies
4
Boosts
0
Views
520
Activity
3w
Embedded Collection View in SwiftUI offset issue
I have a collection view that covers all the screen and it is scrolling behavior is paging. This collection view is embedded in a UIViewRepresentable and used in a SwiftUI app. The issue is that when users rotate the devices, sometimes the CollectionView.contentOffset get miscalculated and shows 2 pages. This is the code that I'm using for the collectionView and collectionViewLayout: class PageFlowLayout: UICollectionViewFlowLayout { override class var layoutAttributesClass: AnyClass { UICollectionViewLayoutAttributes.self } private var calculatedAttributes: [UICollectionViewLayoutAttributes] = [] private var calculatedContentWidth: CGFloat = 0 private var calculatedContentHeight: CGFloat = 0 public weak var delegate: PageFlowLayoutDelegate? override var collectionViewContentSize: CGSize { return CGSize(width: self.calculatedContentWidth, height: self.calculatedContentHeight) } override init() { super.init() self.estimatedItemSize = .zero self.scrollDirection = .horizontal self.minimumLineSpacing = 0 self.minimumInteritemSpacing = 0 self.sectionInset = .zero } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func prepare() { guard let collectionView = collectionView, collectionView.numberOfSections > 0, calculatedAttributes.isEmpty else { return } estimatedItemSize = collectionView.bounds.size for item in 0..<collectionView.numberOfItems(inSection: 0) { let indexPath = IndexPath(item: item, section: 0) let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath) let itemOrigin = CGPoint(x: CGFloat(item) * collectionView.frame.width, y: 0) attributes.frame = .init(origin: itemOrigin, size: collectionView.frame.size) calculatedAttributes.append(attributes) } calculatedContentWidth = collectionView.bounds.width * CGFloat(calculatedAttributes.count) calculatedContentHeight = collectionView.bounds.size.height } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { return calculatedAttributes.compactMap { return $0.frame.intersects(rect) ? $0 : nil } } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { return calculatedAttributes[indexPath.item] } override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { guard let collectionView else { return false } if newBounds.size != collectionView.bounds.size { return true } if newBounds.size.width > 0 { let pages = calculatedContentWidth / newBounds.size.width // If the contentWidth matches the number of pages, // if not it requires to layout the cells let arePagesExact = pages.truncatingRemainder(dividingBy: 1) == 0 return !arePagesExact } return false } override func invalidateLayout() { calculatedAttributes = [] super.invalidateLayout() } override func shouldInvalidateLayout(forPreferredLayoutAttributes preferredAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> Bool { guard let collectionView, #available(iOS 18.0, *) else { return false } return preferredAttributes.size != collectionView.bounds.size } override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext) { guard let customContext = context as? UICollectionViewFlowLayoutInvalidationContext else { return } if let collectionView, let currentPage = delegate?.currentPage() { let delta = (CGFloat(currentPage) * collectionView.bounds.width) - collectionView.contentOffset.x customContext.contentOffsetAdjustment.x += delta } calculatedAttributes = [] super.invalidateLayout(with: customContext) } override func prepare(forAnimatedBoundsChange oldBounds: CGRect) { super.prepare(forAnimatedBoundsChange: oldBounds) guard let collectionView else { return } if oldBounds.width != collectionView.bounds.width { invalidateLayout() } } override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint { guard let collectionView, let currentPage = delegate?.currentPage() else { return .zero } let targetContentOffset = super.targetContentOffset(forProposedContentOffset: proposedContentOffset) let targetPage = targetContentOffset.x / collectionView.frame.width if targetPage != CGFloat(currentPage) { let xPosition = CGFloat(currentPage) * collectionView.frame.width return CGPoint(x: xPosition, y: 0) } return targetContentOffset } // This function updates the contentOffset in case is wrong override func finalizeCollectionViewUpdates() { guard let collectionView, let currentPage = delegate?.currentPage() else { return } let xPosition = CGFloat(currentPage) * collectionView.bounds.width if xPosition != collectionView.contentOffset.x { let offset = CGPoint(x: xPosition, y: 0) collectionView.setContentOffset(offset, animated: false) } } } The full implementation is attached in the .txt file: RotationTestView.txt
Replies
6
Boosts
0
Views
238
Activity
Apr ’26
iOS 26 UITabBar Layout Glitch: Custom Appearance vs. Liquid Glass Effects during Rotation
Hello, I am encountering a UI layout issue on iOS 26 where UITabBar items become squashed or overlapping during device rotation (from Portrait to Landscape). This glitch occurs specifically when a custom UITabBarAppearance is applied. 1. "Liquid Glass" and UITabBar Customization According to TN3106, Apple states: "Starting in iOS 26, reduce your use of custom backgrounds in navigation elements and controls. While the techniques in this document remain valid for iOS 18 and earlier, prefer to remove custom effects and let the system determine the navigation bar background appearance. Any custom backgrounds and appearances you use in the navigation bar might overlay or interfere with Liquid Glass or other effects that the system provides, such as the scroll edge effect." Does this guidance also apply to UITabBar? Specifically, could setting a custom background color via UITabBarAppearance interfere with internal layout constraints required for the Liquid Glass effect to adapt correctly during orientation changes? It appears that the internal UIStackView may fail to recalculate width in time when these system effects are active. 2. Validation of the Layout Workaround To maintain our app's visual identity while resolving this squashing issue, I implemented the following fix within the transition coordinator of my UITabBarController: Code Implementation (Objective-C) [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { // Forcing a layout refresh to synchronize with the rotation animation [weakSelf.tabBar invalidateIntrinsicContentSize]; [weakSelf.tabBar setNeedsLayout]; [weakSelf.tabBar layoutIfNeeded]; } completion:nil]; Is manually invalidating the intrinsic content size an acceptable practice for iOS 26? Or is there a more "system-native" approach to ensure UITabBar layout remains stable and compatible with Liquid Glass, especially when custom appearances are necessary?
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
1
Boosts
0
Views
358
Activity
Apr ’26
iOS 26: Interactive sheet dismissal causes layout hitch in underlying SwiftUI view
I’ve been investigating a noticeable animation hitch when interactively dismissing a sheet over a SwiftUI screen with moderate complexity. This was not the case on iOS 18, so I’m curious if others are seeing the same on iOS 26 or have found any mitigations. When dismissing a sheet via the swipe gesture, there’s a visible hitch right after lift-off. The hitch comes from layout work in the underlying view (behind the sheet) The duration scales with the complexity of that view (e.g. number of TextFields/layout nodes) The animation for programmatic dismiss (e.g. tapping a “Done” button) is smooth, although it hangs for a similar amount of time before dismissing, so it appears that the underlying work still happens. SwiftUI is not reevaluating the body during this (validated with Self._printChanges()), so that is not the cause. Using Instruments, the hitch shows up as a layout spike on the main thread: 54ms UIView layoutSublayersOfLayer 54ms └─ _UIHostingView.layoutSubviews 38ms └─ SwiftUI.ViewGraph.updateOutputs 11ms ├─ partial apply for implicit closure #1 in closure #1 │ in closure #1 in Attribute.init<A>(_:) 4ms └─ -[UIView For the same hierarchy with varying complexity: ~3 TextFields in a List: ~25ms (not noticeable) ~20+ TextFields: ~60ms (clearly visible hitch) The same view hierarchy on iOS 18 did not exhibit a visible hitch. I’ve tested this on an iOS 26.4 device and simulator. I’ve also included a minimum reproducible example that illustrates this: struct ContentView: View { @State var showSheet = false var body: some View { NavigationStack { ScrollView { ForEach(0..<120) { _ in RowView() } } .navigationTitle("Repro") .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Present") { showSheet = true } } } .sheet(isPresented: $showSheet) { PresentedSheet() } } } } struct RowView: View { @State var first = "" @State var second = "" var body: some View { VStack(alignment: .leading, spacing: 12) { Text("Row") .font(.headline) HStack(spacing: 12) { TextField("First", text: $first) .textFieldStyle(.roundedBorder) TextField("Second", text: $second) .textFieldStyle(.roundedBorder) } HStack(spacing: 12) { Text("Third") Text("Fourth") Image(systemName: "chevron.right") } } } } struct PresentedSheet: View { @Environment(\.dismiss) private var dismiss var body: some View { NavigationStack { List {} .navigationTitle("Swipe To Dismiss Me") .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Done") { dismiss() } } } } } } Is anyone else experiencing this and have any mitigations been found beyond reducing view complexity? I’ve filed a feedback report under FB22501630.
Replies
1
Boosts
0
Views
266
Activity
Apr ’26
EXC_BAD_ACCESS in drawHierarchy(in:afterScreenUpdates:) on iOS 26.3.1+ — IOSurface CIF10 decompression crash
We're experiencing an EXC_BAD_ACCESS (SIGSEGV) crash in UIView.drawHierarchy(in:afterScreenUpdates: false) that occurs only on iOS 26.3.1 and later. It does not reproduce on iOS 26.3.0 or earlier. Crash Stack Thread 0 (Main Thread) — EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0 libvDSP.dylib vConvert_XRGB2101010ToARGB8888_vec 1 ImageIO IIOIOSurfaceWrapper_CIF10::CopyImageBlockSetWithOptions 2 ImageIO IIOImageProviderInfo::CopyImageBlockSetWithOptions 3 ImageIO CGImageReadGetBytesAtOffset 4 CoreGraphics CGAccessSessionGetBytes 5 CoreGraphics img_data_lock 6 CoreGraphics CGSImageDataLock 7 CoreGraphics ripc_AcquireImage 8 CoreGraphics ripc_DrawImage 9 CoreGraphics CGContextDrawImage 10 UIKitCore -[UIView(Rendering) drawHierarchy:afterScreenUpdates:] The crash occurs during 10-bit CIF10 → 8-bit ARGB8888 pixel conversion when the IOSurface backing a UIImageView in the view hierarchy is deallocated mid-render. How to Reproduce Display a scrollable list with multiple UIImageViews loaded via an async image library Call drawHierarchy(in: bounds, afterScreenUpdates: false) on visible cells periodically Scroll to trigger image recycling Crash occurs sporadically — more likely under memory pressure or rapid image recycling What We've Tried Both UIKit off-screen rendering approaches crash on iOS 26.3.1: Approach Result drawHierarchy(afterScreenUpdates: false) EXC_BAD_ACCESS in CIF10 IOSurface decompression view.layer.render(in:) EXC_BAD_ACCESS in Metal (agxaAssertBufferIsValid) iOS Version Correlation iOS 26.3.0 and earlier: No crash iOS 26.3.1 (23D8133)+: Crash occurs (~5 events per 7 days) We suspect the ImageIO security patches in iOS 26.3 (CVE-2026-20675, CVE-2026-20634) may have changed IOSurface lifecycle timing, exposing a race condition between drawHierarchy's composited buffer read and asynchronous IOSurface reclamation by the OS. Crash Data We sampled 3 crash events: Event 1 (iOS 26.3.1): 71 MB free memory — memory pressure Event 2 (iOS 26.3.1): 88 MB free memory — memory pressure Event 3 (iOS 26.3.2): 768 MB free memory — NOT memory pressure Event 3 shows this isn't purely a low-memory issue. The IOSurface can be reclaimed even with ample free memory, likely due to async image recycling. Question Is this a known regression in iOS 26.3.1? Is there a safe way to snapshot a view hierarchy containing IOSurface-backed images without risking EXC_BAD_ACCESS? Should drawHierarchy gracefully handle the case where an IOSurface backing store is reclaimed during the render? Any guidance or workarounds would be appreciated. We've also filed this as Feedback (will update with FB number after submission).
Replies
2
Boosts
0
Views
377
Activity
Apr ’26
Keyboard greyed issue
I am facing weird keyboard issue when building the app with Xcode 26 recently. Actual behaviour I need is: But one below is the issue as the keyboard keys are greyed out: Please tell how to resolve this issue
Replies
4
Boosts
0
Views
325
Activity
Apr ’26
Navigation bar flickers when pushing to a different screen
Hi everyone, I’m building a SwiftUI app using NavigationStack and running into a weird nav bar issue. For the setup I have a 'home' screen with a vertical ScrollView and a large edge-to-edge header that extends under the top safe area (using .ignoresSafeArea(edges: .top)). I also have a 'detail' screen with a similar immersive layout, where the header/poster image sits at the top and the ScrollView also extends under the top area. I’m using the native navigation bar on both screens and default back button, not a custom nav bar, and I’m not manually configuring UINavigationBarAppearance, I'm just relying on SwiftUI’s default/automatic toolbar behavior. The problem I’m facing is when I push from home to the detail screen, the top nav area briefly flickers and shows the system navigation bar/material background (white in light mode, black in dark mode). It’s clearly the system material, not the poster/image underneath. The screen initially renders with that nav bar state (white/dark), and only after I start scrolling does it correct itself and visually align with the header/background behind it. What I'm thinking is that maybe the detail screen initially renders with systemBackground, so the nav bar uses its default (standard) appearance on the first frame, and only after layout/interaction, once the image-derived background settles, does it switch to the correct scroll-edge/transparent style. One important thing, if I hide the nav bar on the detail screen using .toolbar(.hidden, for: .navigationBar), the issue disappears completely. So this seems specifically tied to the native nav bar’s initial render/appearance timing during the push, rather than just the layout or image loading. I’d prefer to keep the native nav bar and back button rather than implement a custom approach. Has anyone faced this issue before, or is there a correct way to structure edge-to-edge content under the nav bar so it renders properly on first push? Video of the issue: https://imgur.com/a/OYHtYbp NavigationStack { ScrollView { HeroView() } .ignoresSafeArea(edges: .top) .navigationTitle("Cinema") .toolbarTitleDisplayMode(.inlineLarge) .toolbarBackgroundVisibility(.automatic, for: .navigationBar) .navigationDestination(for: Route.self) { route in DetailView(movie: route.movie) } } var body: some View { ScrollView { HeaderPosterView() } .ignoresSafeArea(edges: .top) .navigationBarTitleDisplayMode(.inline) .toolbarBackgroundVisibility(.automatic, for: .navigationBar) } }
Replies
0
Boosts
1
Views
225
Activity
Apr ’26
DiffableDataSource hangs on apply
About a year ago, I developed and released an app on the App Store (I believe it was running on the Sequoia SDK at the time), and everything was working fine. I’m now revisiting the project using the newer Tahoe SDK, and I’m running into an issue with DiffableDataSource. Specifically, the app hangs and CPU usage spikes to 100% when applying snapshots. Has anyone experienced similar issues after upgrading to newer SDKs? Are there any recent changes or pitfalls with DiffableDataSource (e.g., threading, Hashable requirements, or snapshot handling) that I should be aware of? Any insights or suggestions would be greatly appreciated. extension Section { enum Identifier: Int, CaseIterable { case main } enum Item: Hashable { case file(FileViewData) } } struct FileViewData: Equatable, Hashable, Identifiable { let id: String let name: String var accessoryViewData: KTFDownloadAccessoryViewData init( id: String, name: String, accessoryViewData: KTFDownloadAccessoryViewData = .nothing ) { self.id = id self.name = name self.accessoryViewData = accessoryViewData } } public enum KTFDownloadAccessoryViewData: Equatable, Hashable { case nothing case selected(SelectedState) case completed public enum SelectedState: Equatable, Hashable { case nothing case waiting case downloading(Double) } } When I changed FileViewData as below, no hangs but item appearance doesn't change of course. struct FileViewData: Equatable, Hashable, Identifiable { let id: String let name: String var accessoryViewData: KTFDownloadAccessoryViewData init( id: String, name: String, accessoryViewData: KTFDownloadAccessoryViewData = .nothing ) { self.id = id self.name = name self.accessoryViewData = accessoryViewData } func hash(into hasher: inout Hasher) { hasher.combine(id) } static func == (lhs: FileViewData, rhs: FileViewData) -> Bool { return lhs.id == rhs.id } }
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
1
Boosts
0
Views
150
Activity
Apr ’26
Window size of iOS app running on Mac
I need constraint the window size for an iOS app running on Mac. That's easy for a MacApp, using self.window?.minSize.width = 450 self.window?.maxSize.width = 450 or use func windowDidResize(_ notification: Notification) { } but how to achieve it in UIKit ?
Replies
3
Boosts
0
Views
550
Activity
Apr ’26
Potentially Unfair Limitation for Third-Party Keyboard Developers
When developing a custom keyboard on iOS, even after enabling Full Access (RequestsOpenAccess = true), it is still not possible to record audio — the recording simply does not start. This is despite the fact that: the user is explicitly warned the user provides informed consent by enabling Full Access According to Apple’s documentation: https://developer.apple.com/documentation/uikit/configuring-open-access-for-a-custom-keyboard “However, with RequestsOpenAccess set to true, the keyboard has all the capabilities in the preceding list.” At the same time, the preceding list includes: “No access to microphone and speaker” This creates ambiguity. The wording suggests that enabling Full Access should lift prior restrictions, yet in practice, microphone access remains unavailable to third-party keyboards. Why this is concerning With Full Access enabled, a keyboard already has: network access the ability to transmit user input From a privacy standpoint, this is already highly sensitive. Preventing microphone access while allowing these capabilities appears inconsistent. Meanwhile, Apple’s own system keyboard supports voice dictation, which creates a functional gap between first-party and third-party keyboards. Competition perspective This raises a broader question about equal access to platform capabilities. Restricting third-party keyboards from using the microphone — while first-party solutions can — may be seen as: unequal treatment of developers a limitation of competition in input methods Such differences are increasingly scrutinized under EU regulations like the Digital Markets Act and Article 102 TFEU, which emphasize fair access to platform features and prohibit self-preferencing by dominant platforms. Request for clarification Is microphone access intentionally restricted for all third-party keyboards, even with Full Access enabled? If so, what is the technical or policy justification? Are there plans to provide a secure and user-consented way to enable audio input for custom keyboards? Clarification on this would help developers better understand platform limitations and design decisions.
Replies
0
Boosts
0
Views
245
Activity
Apr ’26
UITextView cursor sometimes jumps up when pressing arrow down key and setting typingAttributes
My app uses TextKit 1 and unfortunately still cannot migrate to TextKit 2 because of some bugs (for instance in FB17103305 I show how NSTextView.shouldDrawInsertionPoint has no effect, but I opened that feedback exactly one year ago and it still has no answer). Unfortunately TextKit 1 has another bug which causes the text cursor to jump unpredictably up or down when pressing the arrow keys and setting UITextView.typingAttributes. Run the code below on iPhone 17 Pro Max Simulator. Scroll the text down until you see “Header 2”. Place the text cursor after “# “. Press the arrow down key twice to move the cursor two lines down. The cursor moves to the top of the view instead. Continuing to press the arrow keys up and down results in the cursor sometimes moving as expected, other times jumping around wildly. Does anyone know a workaround? I created FB22382453. class TextView: UITextView, UITextViewDelegate { override func awakeFromNib() { let _ = layoutManager delegate = self let header = textAttributes(fontSize: 30) let body = textAttributes(fontSize: 15) let string = NSMutableAttributedString(string: String(repeating: "a", count: 2681) + "\n", attributes: body) string.append(NSAttributedString(string: """ # Header 1 """, attributes: header)) string.append(NSMutableAttributedString(string: String(repeating: "a", count: 5198) + "\n", attributes: body)) string.append(NSAttributedString(string: """ # Header 2 """, attributes: header)) string.append(NSMutableAttributedString(string: String(repeating: "a", count: 7048) + "\n", attributes: body)) textStorage.setAttributedString(string) } func textViewDidChangeSelection(_ textView: UITextView) { typingAttributes = textStorage.attributes(at: selectedRange.location - 1, effectiveRange: nil) } private func textAttributes(fontSize: Double) -> [NSAttributedString.Key: Any] { var textAttributes = [NSAttributedString.Key: Any]() textAttributes[.font] = UIFont(name: "Courier", size: fontSize) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.minimumLineHeight = round(fontSize * 1.3) paragraphStyle.maximumLineHeight = paragraphStyle.minimumLineHeight textAttributes[.paragraphStyle] = paragraphStyle return textAttributes } }
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
0
Boosts
0
Views
154
Activity
Mar ’26
Left-flick and right-flick gestures with VoiceOver and UIAccessibilityReadingContent
Hi, I have an app that displays lines of text, that I want to make accessible with VoiceOver. It's based on a UITextView. I have implemented the UIAccessibilityReadingContent protocol, following the instructions in https://developer.apple.com/videos/play/wwdc2019/248 and now users can see the screen line by line, by moving their fingers on the screen. That works fine. However, users would also like to be able to use left-flick and right-flick to move to the previous or next line on the screen, and I haven't been able to make this work. I can see that left-flick triggers accessibilityPreviousTextNavigationElement and right-flick triggers accessibilityNextTextNavigationElement, but I don't understand what these variables should be.
Replies
1
Boosts
0
Views
1.5k
Activity
Apr ’26
Scene resizing on iPad breaks UIPageViewController's setViewControllers
The following is verbatim of a feedback report (FB22367951) I submitted, shared here as someone else might be interested to see it. I have reproduced this bug on iPadOS 26.3.1 (a) and 26.4. During scene resizing on iPad, UIPageViewController's setViewControllers method fails to do its work. The navigation starts and for a brief moment you can see the new view controller coming from the expected direction, but shortly after it fails and stays on the same [current] view controller. It doesn't even call the completion handler when it fails. When the navigation succeeds (due to not resizing a scene during the navigation) after previously failing at least once, the completion handler is sometimes called more than once. I have created a demo project, which I have pushed to this repo: https://github.com/galijot/SceneResize-Breaks-UIPageViewController I have also attached a zip of the project to this report.
Replies
0
Boosts
0
Views
262
Activity
Mar ’26
Left navigation bar items become invisible after rotating device and presenting detail view in split view
A user of my app, whose main view is a split view, reported an issue which causes the left navigation bar items to disappear without apparent reason if they rotate the device and later show the detail view, preventing them from using the back button to show the root view again. Am I doing something wrong or is it a bug? I can reproduce the issue with the following steps: Create a new document-based iOS app (as it uses scenes by default, as opposed to a regular app). Paste the code below. In the target build settings, delete "Launch Screen Interface File Base Name" and set "Launch Screen (Generation)" to YES. Without this step, for some reason, the issue doesn't happen. Launch the app in iPhone Simulator. Tap the top left button to show the root view, then the “detail” button to show the detail view. The left navigation bar button is still visible. Rotate the Simulator window right, then left again. Tap the top left button to show the root view, then the “detail” button to show the detail view. Now the left navigation bar button is invisible. Rotating the device right and left again solves the issue. I filed FB22363118. class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { window = UIWindow(windowScene: scene as! UIWindowScene) let split = SplitViewController() window!.rootViewController = split window!.makeKeyAndVisible() split.showDetail() } } class SplitViewController: UISplitViewController, UISplitViewControllerDelegate { var detailNavigationViewController: UINavigationController! init() { super.init(nibName: nil, bundle: nil) detailNavigationViewController = UINavigationController(rootViewController: DetailViewController()) viewControllers = [UINavigationController(rootViewController: RootViewController())] } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func showDetail() { showDetailViewController(detailNavigationViewController, sender: nil) } func showRoot() { (viewControllers.first as? UINavigationController)?.popViewController(animated: true) } } class RootViewController: UIViewController { override func loadView() { navigationItem.title = "root" let button = UIButton(primaryAction: UIAction(handler: { [self] _ in (splitViewController as! SplitViewController).showDetail() })) button.setTitle("detail", for: .normal) view = button } } class DetailViewController: UIViewController { override func loadView() { navigationItem.title = "detail" view = UIView() registerForTraitChanges([UITraitHorizontalSizeClass.self]) { (self: Self, previousTraitCollection) in if previousTraitCollection.horizontalSizeClass != self.traitCollection.horizontalSizeClass { self.updateBarButtons() } } updateBarButtons() } private func updateBarButtons() { navigationItem.leftBarButtonItem = UIBarButtonItem(primaryAction: UIAction(image: UIImage(systemName: "sidebar.leading")) { [self] _ in (self.splitViewController as! SplitViewController).showRoot() }) navigationItem.rightBarButtonItem = UIBarButtonItem(title: "right") } }
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
0
Boosts
0
Views
98
Activity
Mar ’26
IOS Swift touch screen issue
MyOwnKeyboard Pad app has 4 text views with textfields that use touch screen for editing. There is one view, Compose, that has a textfield and a textview (UIRepresentable). The app enters text into the view using textfield buttons. The app has total control of editing. When entering text if the screen is touched it conflicts the cursor position and creates an "out of bounds" failure. In that view the app does not need any touch events. I need a method in UIRepresentable to disable the touch event. I am not familiar with UIRepresentable as this code was provided by Apple to solve a 16 bit unicode character issue. What would be the code to disable touch events in the UIRepresentable compose view. The app is free for a while until this problem is fixed. It is for iPads 11"+ . The name in the app store is MyOwnKeyboard Pad. I know some great engineer will find the answer. DTS tried. Thanks to all, maybe I'll sell some. Charlie 25mar26
Replies
1
Boosts
0
Views
185
Activity
Mar ’26
UISheetPresentationController Disable Liquid Glass For Foreground Elements Within a Sheet
Hello just wondering if there is a supported way to disable the liquid glass effect that is passed down to every subview within a sheet using the medium or smaller detents? There are certain views with information in them within this sheet that I do not want to become semi transparent but I want to keep the background view of the sheet using the default liquid glass effect.
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
2
Boosts
0
Views
210
Activity
Mar ’26
iPadOS 26: How to prevent new scene creation when sharing a file to my app?
Many different types of files can be opened in my app. If a user, for example, views a file in the Files app and chooses to share the file, they can select my app from the list of options. My app is then given a chance to handle the file as needed. This works just fine in most cases. However, on iPadOS 26, if the user has set the iPad's Multitasking to either Windowed Apps or Stage Manager, then any time they choose to share a file with my app, a new scene (and window) is created. The user is usually not even aware that more and more windows/scenes are being created. It's only after they long-press on the app icon and select Show All Windows (or look under the Open Windows section) do they see far more windows than expected. Under iPadOS 17, 18, or with 26 set to Full Screen Apps, sharing a file to my app simply uses an existing scene, even if the user has explicitly created multiple scenes. A new scene is never created when sharing a file to my app unless there is no existing scene. Due to the nature of my app, even if the user has setup the iPad with Windowed App or Stage Manager under iPadOS 26, it would be far better if a new scene was not created and an existing scene was used. In other words, have it behave just as it does under iPadOS 17 or 18, or with 26 set as Full Screen Apps. Is there any way to configure an app to always use an existing scene when a file is shared with the app? My app is written with UIKit. Under iPadOS 26 with multitasking set to Windowed Apps or Stage Manager, sharing a file with my app results in the UIApplicationDelegate method application(_:configurationForConnecting:options:) being called. At this point a new scene is already in the process of being created. I don't see anything that can be set in the Info.plist. I do not see any relevant UIApplicationDelegate methods. Am I missing something or is this not possible?
Replies
0
Boosts
0
Views
216
Activity
Mar ’26
Layout glitch after rotation when using UIWindowScene sizeRestrictions on iPadOS 26
Hi everyone, I am experiencing a strange rendering issue on iPadOS 26 when sizeRestrictions.minimumSize is set on a UIWindowScene. After rotating the device and then rotating it back to the original orientation, the window appears to be stretched based on its previous dimensions. This resulting "stretched" area does not resize or redraw correctly, leaving a significant black region on the screen. Interestingly, as soon as I interact with the window (e.g., a slight drag or touch), the UI snaps back to its intended state and redraws perfectly. Here is a sample code and capture of behavior. class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } windowScene.sizeRestrictions?.minimumSize = CGSize( width: 390, height: 844 // larger than the height of iPad in landscape ) // initialize... } } Has anyone else encountered this behavior? If so, are there any known workarounds to force a layout refresh or prevent this "ghost" black area during the rotation transition? Any insights would be greatly appreciated. Thanks!
Replies
1
Boosts
0
Views
254
Activity
Mar ’26