Hi,
I’m seeing a crash when running my app on iOS 18 simulators or devices using Xcode 26 beta 3.
My app’s minimum deployment target is iOS 17, and the crash does not happen when running from Xcode 16.4.
The crash occurs specifically at this line:
return UIStoryboard(name: storyboard.rawValue, bundle: nil)
.instantiateViewController(withIdentifier: view.rawValue)
Crash Details:
** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: 'Could not instantiate class named _TtGC5UIKit17UICoreHostingViewVCS_21ToolbarVisualProvider8RootView_ because no class named _TtGC5UIKit17UICoreHostingViewVCS_21ToolbarVisualProvider8RootView_ was found; the class needs to be defined in source code or linked in from a library (ensure the class is part of the correct target)'
*** First throw call stack:
(0x191c3321c 0x18f0cdabc 0x191c91ea0 0x19d740774 0x19d740a18 0x19d740cac 0x194626680 0x194dbc784 0x19d740890 0x19d740cac 0x1949aadd8 0x19d740890 0x19d740a18 0x19d740cac 0x194802e24 0x1945f008c 0x194ed1808 0x107a8bfa0 0x107a8c05c 0x1945ec128 0x19d740890 0x19d740cac 0x1945eba60 0x19d740890 0x19d740a18 0x19d740cac 0x1945f07dc 0x1945eaea4 0x19492ee80 0x10763de00 0x1076e56fc 0x1076e5674 0x1076e5e04 0x19496108c 0x194f9b9a0 0x1949072c4 0x194f998cc 0x194f9af04 0x19445139c 0x19445ac28 0x194467508 0x1079afaec 0x1079aff5c 0x1944189a0 0x194417be4 0x1944114e4 0x194411404 0x194410ab4 0x19440c1e4 0x191b28a8c 0x191b288a4 0x191b28700 0x191b29080 0x191b2ac3c 0x1ded09454 0x19453d274 0x194508a28 0x1073564f4 0x1b89fff08)
terminating due to uncaught exception of type NSException
The crash occurs immediately at app launch, when attempting to load a storyboard-based UITabBarController.
Works as expected on:
Xcode 16.4 + iOS 18 (simulator/device)
Xcode 26 beta 3 + iOS 26 (simulator/device)
Running from Xcode 26 beta 3 onto iOS 18 simulators or devices and it immediate crash from the particular storyboard
Setup:
Xcode: 26 beta 3
macOS: 15.5
iOS Simulators: iOS 18.5
Minimum deployment target: iOS 17
UIKit-based app (not using SwiftUI)
No custom toolbars or host views in use explicitly
Is this a known compatibility issue when building with the iOS 26 SDK and running on iOS 18?
Are there any workarounds or recommendations for running apps targeting iOS 17+ on iOS 18 simulators when using Xcode 26?
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Posts under UIKit tag
200 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
A bottom accessory view is set on the UITabBarController. When changing the window size either by dragging the resizing grip or when going to portrait mode, the accessory view shrinks down to the smaller width. When resizing the window to make it larger, the accessory view doesn’t resize to the full available width.
During a workshop setup by Apple, folks from Apple told me that the view set as the content view of the UITabAccessory should not have its frame changed, either by using Auto Layout or by setting the frame. It seems logical since the view in the bottom accessory is supposed to resize accordingly to several factors, like when going inline inside the tab bar.
Am I missing something? Maybe there is additional setup required not mentioned in the dedicated video.
Feedback is FB19017330. It contains a sample project and videos demonstrating the issue. Reproduced on Xcode 26 beta 6 (17A5305f)
I copy and paste the sample code that setups the bottom accessory for good measure.
final class MiniPlayer: UIView {
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
label.text = "Mini Player"
label.numberOfLines = 0
label.textAlignment = .center
addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: centerXAnchor),
label.centerYAnchor.constraint(equalTo: centerYAnchor)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - View Controller
class ViewController: UIViewController {
let rootTabBarController = UITabBarController()
let miniPlayer = MiniPlayer()
override func viewDidLoad() {
super.viewDidLoad()
let items: [UITab] = [
UITab(title: "Tab 1", image: UIImage(systemName: "archivebox.fill"), identifier: "tab-1") { _ in
UIViewController()
},
UITab(title: "Tab 2", image: UIImage(systemName: "books.vertical.fill"), identifier: "tab-2") { _ in
UIViewController()
},
UISearchTab { _ in
UIViewController()
}
]
rootTabBarController.tabs = items
rootTabBarController.view.backgroundColor = .secondarySystemBackground
view.addSubview(rootTabBarController.view)
rootTabBarController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
rootTabBarController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
rootTabBarController.view.topAnchor.constraint(equalTo: view.topAnchor),
rootTabBarController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
rootTabBarController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
rootTabBarController.bottomAccessory = UITabAccessory(contentView: miniPlayer)
}
}
@MainActor
class KeyboardObserver {
var token: NotificationCenter.ObservationToken!
func registerObserver(screen: UIScreen) {
let center = NotificationCenter.default
token = center.addObserver(of: screen, for: .keyboardWillShow) { keyboardState in
print("+++ Keyboard showed up!")
}
}
}
The notification is never called.
The sample code from the sessions also does not work for me.
let keyboardObserver = NotificationCenter.default.addObserver(
of: UIScreen.self
for: .keyboardWillShow
) { message in
UIView.animate(
withDuration: message.animationDuration, delay: 0, options: .flushUpdates
) {
// Use message.endFrame to animate the layout of views with the keyboard
let keyboardOverlap = view.bounds.maxY - message.endFrame.minY
bottomConstraint.constant = keyboardOverlap
}
}
@MainActor
class KeyboardObserver {
func registerObserver(screen: UIScreen) {
let center = NotificationCenter.default
let token = center.addObserver(
of: screen,
for: .keyboardWillShow
) { keyboardState in
let startFrame = keyboardState.startFrame
let endFrame = keyboardState.endFrame
self.keyboardWillShow(startFrame: startFrame, endFrame: endFrame)
}
}
func keyboardWillShow(startFrame: CGRect, endFrame: CGRect) {}
}
I’m trying to detect a double-tap action on a UIButton. There seem to be two possible approaches:
Using a UITapGestureRecognizer with numberOfTapsRequired = 2.
Using the .touchDownRepeat event of UIControl.Event.
What is the recommended approach for reliably handling double-taps on UIButton? Are there any practical differences in terms of behavior, performance, or best practices between these two methods?
Additionally, I noticed that UIControl.Event defines a large set of events (like .editingChanged, .valueChanged, etc.).
Can all these events be applied to any UIControl subclass such as UIButton, or are they only valid for specific controls like UITextField, UISlider, etc.?
If not all events are supported by all controls, what is the rationale behind exposing them under a shared UIControl.Event enum?
Thanks in advance!
The default cell height is 44pt in iOS 18 and 52pt in iOS 26. I'm trying to reduce the height back to 44pt in one screen that needs to fit as much content on screen as possible. How do you do that when using UIListContentConfiguration?
I expected this would do the trick but alas it doesn't reduce the cell height.
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Item> { cell, indexPath, item in
cell.contentConfiguration = {
var config = UIListContentConfiguration.valueCell()
config.text = "Title"
config.secondaryText = "Value"
// This only removes horizontal margins, does not change vertical margins
config.axesPreservingSuperviewLayoutMargins = []
config.directionalLayoutMargins = .zero
return config
}()
}
On iPhone SE (2nd/3rd generation) running iOS 26 beta , the safeAreaInsets.top unexpectedly returns 0 instead of the expected 20 points, causing UI elements that rely on safe area layout to be overlapped by the status bar.
You can see that i works fine with iOS 18, whereas iOS 26 the status bar is overlapped. Is this a known bug or there is new API changes that I might not be aware of.
I’m working with UIButton and I’d like to register multiple UIControl.Events (e.g. .touchUpInside, .touchDown, .touchCancel, .primaryActionTriggered) using the same selector.
For example:
button.addTarget(self,
action: #selector(handleButtonEvent(_:forEvent:)),
for: [.touchUpInside, .touchDown, .touchCancel, .primaryActionTriggered])
@objc func handleButtonEvent(_ sender: UIButton, forEvent event: UIEvent) {
// How do I tell which UIControl.Event triggered this?
}
From my understanding:
If I use the single-parameter version (@objc func handleButtonEvent(_ sender: UIButton)), I can’t distinguish which event fired.
If I use the two-parameter version with UIEvent, I can inspect touch.phase or event.type, but that feels indirect.
Questions:
Is there a recommended way to directly know which UIControl.Event caused the selector to fire?
Is sharing a single selector across multiple control events considered a good practice, or is it more common to register separate selectors per event?
Would appreciate guidance on what Apple recommends here.
I’m working with UIButton and finding different examples for event handling. Currently, I have a single action method like this, which receives the sender and the UIEvent:
@objc func buttonHandler(_ sender: UIButton, forEvent event: UIEvent) {
if let touches = event.allTouches, let touch = touches.first {
switch touch.phase {
case .began: print("TouchDown")
case .ended:
if sender.bounds.contains(touch.location(in: sender)) {
print("TouchUpInside")
} else {
print("TouchUpOutside")
}
case .cancelled: print("TouchCancel")
default: break
}
}
if event.type == .presses {
print("PrimaryActionTriggered")
}
}
Is this considered best/recommended practice in UIKit, or should I use separate selector methods for each event type (e.g. .touchDown, .touchUpInside, .touchUpOutside) using addTarget(_:action:for:)?
Are there any advantages or disadvantages to using a single handler with UIEvent versus multiple selectors for UIControlEvents?
Thanks in advance!
I'm using a standard UITabBarController on iPad. When first selecting any tab, the corresponding menu bar items are grayed out for this view controller. It's only when I tap any button in that view controller, like in the toolbar, that the view controller truly becomes the first responder (you can see the sidebar selection turns to gray from blue), enabling those menu bar items.
Am I doing something wrong here?
A video of the issue can be found here: https://mastodon.social/@nicoreese/114949924393554961
AppDelegate:
...
builder.insertChild(MenuController.viewModeMenu(), atStartOfMenu: .view)
class func viewModeMenu() -> UIMenu {
let listViewModeCommand = UICommand(
title: String(localized: "As List"),
image: UIImage(systemName: "list.bullet"),
action: #selector(GamesViewController.setListViewMode),
propertyList: SettingsService.ViewMode.list.rawValue
)
...
let viewModeMenu = UIMenu(
title: "",
image: nil,
identifier: .viewModeMenu,
options: .displayInline,
children: [listViewModeCommand...]
)
return viewModeMenu
}
GamesViewController:
@objc
func setListViewMode() {
updateViewMode(.list)
}
I can do this, but then the sidebar selection instantly turns gray, which looks odd and other system apps do not behave this way.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
becomeFirstResponder()
}
override var canBecomeFirstResponder: Bool {
return true
}
I'm using multiple scenes in my iPad app.
When I open a new scene from my main window, that new window is always the same size as the previous window.
When I make the main window very small and then create a new scene, that new window is also tiny. When I make the main window very big, you guessed it.
UIWindowScene.sizeRestrictions does not seem to help here. How can I give new windows a default size (it's okay if they're resizable after presenting)? This is such a weird behavior.
Video of the problem in action: https://mastodon.social/@nicoreese/115033539035249909
It appears from my testing that the following is true:
If you close all windows of an app, the app terminates entirely. Minimizing the last window sends it into multitasking. This is different from previous behavior and might have implications on your app's logic.
If you close the last window and quickly tap the app icon again, that same window will come back. Waiting a second before tapping the app icon will bring up the main window (likely because by that point the app was terminated and relaunched).
Is this expected behavior? I did not see any announcement of this.
I find this a bit counterintuitive and would presume that closing the last window would just send the app to multitasking, just like previously. Quitting the app should be reserved by swiping up on it in the multitasking UI or with a new context menu command.
I do the majority of my test development on an iPhone 16 Pro in the iOS Simulator. As part of my UI rework to maintain compatibility with iOS 26 I decided to run on an older device with a small screen size for testing. The smallest device that supports iOS 26 is the iPhone SE 2nd Gen and 3rd Gen.
Take a look at the image below:
On the left is the iPhone SE 2nd Gen. On the right iPhone 16 Pro.
It looks like the UITabBar which is from a UITabBarController is sized too tall. The actual Tab Bar itself is 62px while the container that houses it is 83px. Yes there should be some top/bottom space to allow for the Liquid Glass Effect to overlap as it often spills outside it's bounds but this feels like far too much.
Looking at them side by side, the iPhone SE Tab Bar actually takes up more space which is not ideal for users who are working on a smaller screen to begin with and have less real estate.
It looks like the bottom space is allowable room for the 'swipe to dismiss line' however these devices use Touch ID and that line is never present. Feels like the 83px for the Tab Bar should be reduced on these devices to allow for more useable screen real estate. Is this a design oversight as iOS 26 seems to be built predominantly for Face ID Devices? Just wondering if any Apple Design Engineers can chime in to see if this will be addressed in a future beta?
The only way to change it at this stage is with a CGAffineTransform however this does not impact the '_UITabBarContainerWrapperView' that sits behind it.
Also, on that note. The '_UITabBarContainerWrapperView' sometimes seems to be clear and other times displays a solid system background color. Is there anyway to control this? Many of my views both SwiftUI and UIKit have differing behaviour. My understanding is the idea of iOS 26 is for your app's content to be visible behind the Tab Bar, however the content is obscured by '_UITabBarContainerWrapperView' in many of my views and I can not figure out how to change that.
Thanks!
When working with modal sheet views in iOS 26 I animate changes to detent size like this:
if let sheet = self.sheetPresentationController {
let newDetent = 400
sheet.animateChanges {
sheet.invalidateDetents()
sheet.detents = [.custom(resolver: { context in newDetent })]
}
}
What I have found is that when using a Touch ID Device the input detent will be smaller when the system presents it. If I set the detent size to be 400, on an iPhone 16 Pro it will be 400px but on an iPhone SE 2nd Gen it will be 366.
It seems to be consistently 34px shorter on devices with a Touch ID Square Shaped Screen. This 34px corresponds to the bottom safe area. This feels like a bug to me. I would expect the detent size to match what I assign on all devices.
I will monitor if this is fixed in a future beta but it is present as of iOS 26 Beta 5. In the meantime I have built this helper function which will then correctly size it on all devices:
static func getDetent(basedOn inputValue: Double) -> CGFloat {
if let window = UIApplication.shared.windows.first {
if window.safeAreaInsets.bottom > 0 {
// Face ID Device, Bottom Inset of 34
return inputValue
} else {
// Touch ID Device, Bottom Inset of 0
return inputValue + 34
}
} else {
// Fallback, Return Input Value
return inputValue
}
}
This impacts when animating detents as per above but also when presenting a Sheet View for the first time and assigning a custom detent.
Thanks!
The app becomes unresponsive when pushing a new page. The screen is covered by the _UIParallaxOverlayView class, blocking all gestures.
Are there any scenarios where the transition animation might suddenly stop mid-process?
Or could you provide more information to help me troubleshoot this issue?
I noticed:
When the issue occurs, the FromViewController is displayed on the screen. The ToViewController also exists in the view tree, but it's not visible on the screen.
_UIParallaxOverlayView only appears on iOS 18 and above.
The animation appears to be controlled by +[UIView _fluidParallaxTransitionsEnabledWithTraitCollection:], which is _os_feature_enabled_impl("UIKit", "fluid_parallax_transitions"). Reference
In our current code, the properties of XIB controls are added with weak. However, we encounter some crashes due to accessing wild pointers of controls when a memory warning occurs.
Colleagues from our architecture team said that they had specifically consulted Apple's technical staff before, and the reply was that strong should be used for modification, as it would make the memory more stable. They also mentioned that the statement in the official documentation is incorrect and hasn't been updated.
May I ask whether strong or weak should be used for XIB control properties? What is your latest standard answer?
I would like my users to be able to switch to the search tab (in the sidebar) on iPad and immediately start typing. This is not possible. Calling becomeFirstResponder in viewDidLoad and viewWillAppear does not work. Only in viewDidAppear it does, but that comes with a significant delay between switching to the tab and the search field becoming active. Is there something else I can do?
FB19588765
let homeTab = UITab(
title: "Home",
image: UIImage(systemName: "house"),
identifier: "Home"
) { _ in
UINavigationController(rootViewController: ViewController())
}
let searchTab = UISearchTab { _ in
UINavigationController(rootViewController: SearchViewController())
}
let tabBarController = UITabBarController(tabs: [
homeTab, searchTab
])
tabBarController.mode = .tabSidebar
class SearchViewController: UIViewController {
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .systemBackground
self.title = "Search"
self.navigationItem.searchController = searchController
self.navigationItem.preferredSearchBarPlacement = .integratedCentered
searchController.becomeFirstResponder() // Does not work.
searchController.searchBar.becomeFirstResponder() // Does not work.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
searchController.searchBar.becomeFirstResponder() // Does not work.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
searchController.searchBar.becomeFirstResponder() // Works. But comes with a significant delay.
}
}
The isEnabled property on UITabBarItem no longer disables tab bar items as expected in iOS 26. Setting tabBarItem.isEnabled = false on a view controller has no visual or functional effect - the tab remains interactive and doesn't show the disabled state.
While testing my application on iOS beta 26, I am experiencing issues with the native UISegmentedControl component from UIKit. After implementing the control, I noticed that I am unable to switch to the second segment option—the selection remains fixed on the first segment regardless of user interaction. I have already reviewed the initial configuration of the control, the addition of the segments, and the implementation of the target-action, but the issue persists. I would like to understand what could be causing this behavior and if there are any specific adjustments or workarounds for iOS 26.
I created a minimal application containing only a UISegmentedControl to clearly demonstrate the issue.
After Picture-in-Picture is opened on the camera interface, the custom UI cannot be displayed. Is there any way to make the custom UI visible? If custom UI cannot be displayed, how do teleprompter-type apps in the store manage to show custom teleprompter text within the camera?
We have encountered a problem on iOS 26. When switching to dark mode, the color of all subviews (font color, background color, etc.) of the Sidebar (Primary View) of UISplitViewController will not change. For example, if it is set to the color of UIColor.label, it will always be black and will not be white in dark mode.
On Xcode, just create a UISplitViewController in Storyboard without changing any settings, and run it directly to see the following:
The title of the Navigation Bar defaults to the label color, and it is still black after switching to dark mode.
There is no such problem in the Secondary View or other places.
This problem has occurred since iOS 26 beta 3, and iOS 26 beta 4 is now the same. But beta 1 and beta 2 have no problem.
I'm not sure if this is a bug, or if there is something that needs to be changed to adapt to iOS 26?