With iPadOS 18, the UITabBar now defaults to the floating style. I successfully reverted the tab bar to its traditional style by overriding the UITabBarController's horizontalSizeClass property:
self.tabBarController?.traitOverrides.horizontalSizeClass = .unspecified
When I launch the app on my Mac using Apple Silicon, TWO tab bars appear:
One appears at the bottom of the screen, like a traditional tab bar.
The second tab bar is still embedded in the app toolbar in its floating style.
Is this a bug? How do you ensure that overriding the horizontalSizeClass will remove/hide the floating tab bar when running an app on Apple Silicon? TIA!
(Demonstrated on a test project)
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hello,
I was wondering if someone could clear-up my thinking here.
e.g. consider the code below...
It has a rootView with a navlink to a childView which in turn has navlinks to GrandchildViews.
The root view uses basic navLInks NavigationLink{View} label: {View}
The child view uses type-based navLinks navigationLink(value:) {View} and .navigationDestination(for:) {View}
I would expect the basic navlinks to work in the root view and the type-based ones to work in the child view. However it appears that both are active when one taps on a link in the child view.
e.g. User actions:
Start -> RootView is only view on the stack -> (tap on ‘Child View’) -> ChildView is top of the stack -> tap on ‘Alice’ -> a second ChildView is top of the stack with a GrandchildView underneath….
Why does this happen, why are the basic links also applied to the childView's links?
Thanks.
struct Thing: Identifiable, Hashable {
let id = UUID()
let name: String
}
struct RootView: View {
var body: some View {
NavigationStack {
List {
NavigationLink {
ChildView()
} label: {
Label("Child View", systemImage: "figure.and.child.holdinghands")
}
NavigationLink {
Text("Hello")
} label: {
Label("Another navLink item in the list", systemImage: "circle")
}
}
.padding()
}
}
}
struct ChildView: View {
private var things = [
Thing(name: "Alice"),
Thing(name: "Bob"),
Thing(name: "Charlie"),
]
var body: some View {
Text("This is the child view")
List {
ForEach(things) { thing in
NavigationLink(value: thing) {
Text(thing.name)
}
}
}
.navigationTitle("Child View")
.navigationDestination(for: Thing.self) { thing in
GrandchildView(thing: thing)
}
}
}
struct GrandchildView: View {
let thing: Thing
var body: some View {
Text("This is the GrandchildView: \(thing.name)")
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
My App always encounter with CoreAutoLayout invade
My SnapKit layout constraint as follow:
popBgView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.leading.equalTo(assistantTeacherView.snp.trailing).offset(.isiPad ? -50 : -40)
if TTLGlobalConstants.isCompactScreen320 {
make.width.lessThanOrEqualTo(300)
} else {
let widthRatio = .isiPad ? 494.0 / 1024.0 : 434.0 / 812.0
make.width.lessThanOrEqualTo(TTLGlobalConstants.screenWidth * widthRatio)
}
bubbleViewRightConstraint = make.trailing.equalToSuperview().constraint
}
.....
popBgView.addSubview(functionView)
msgLabel.snp.remakeConstraints { make in
make.leading.equalToSuperview().inset(Metric.msgLabelHorizantalInset)
make.centerY.equalToSuperview()
make.trailing.lessThanOrEqualToSuperview().inset(Metric.msgLabelHorizantalInset)
make.top.equalTo(Metric.msgLabelVerticalInset)
}
functionView.snp.makeConstraints { make in
make.leading.equalTo(msgLabel.snp.trailing).offset(Metric.msgLabelFunctionSpacing)
make.centerY.equalToSuperview()
make.trailing.equalToSuperview().offset(-Metric.msgLabelHorizantalInset)
}
msgLabel and functionView superview is popBgView
However, when I try remove from superview for functionView, There is low probability crash:
OS Version: iOS 16.1.1 (20B101)
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: SEGV_NOOP
Crashed Thread: 0
Application Specific Information:
Exception 1, Code 1, Subcode 14967683541490370463 >
KERN_INVALID_ADDRESS at 0xcfb7e4e0f8fe879f.
Thread 0 Crashed:
0 CoreAutoLayout 0x382555f44 -[NSISEngine positiveErrorVarForBrokenConstraintWithMarker:errorVar:]
1 CoreAutoLayout 0x382555e9c -[NSISEngine positiveErrorVarForBrokenConstraintWithMarker:errorVar:]
2 CoreAutoLayout 0x3825557e4 -[NSISEngine removeConstraintWithMarker:]
3 CoreAutoLayout 0x382555198 -[NSLayoutConstraint _removeFromEngine:]
4 UIKitCore 0x34d87961c __57-[UIView _switchToLayoutEngine:]_block_invoke
5 CoreAutoLayout 0x382556e8c -[NSISEngine withBehaviors:performModifications:]
6 UIKitCore 0x34d8a1c38 -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]
7 UIKitCore 0x34d7f01b0 __57-[UIView _switchToLayoutEngine:]_block_invoke_2
8 UIKitCore 0x34d879770 __57-[UIView _switchToLayoutEngine:]_block_invoke
9 CoreAutoLayout 0x382556e8c -[NSISEngine withBehaviors:performModifications:]
10 UIKitCore 0x34d8a1c38 -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]
11 UIKitCore 0x34d8a1848 __45-[UIView _postMovedFromSuperview:]_block_invoke
12 UIKitCore 0x34e7ff8d0 -[UIView _postMovedFromSuperview:]
13 UIKitCore 0x34d85e3c8 __UIViewWasRemovedFromSuperview
14 UIKitCore 0x34d85b1a4 -[UIView(Hierarchy) removeFromSuperview]
15 Collie-iPad 0x203001550 [inlined] InClassAssistantView.functionView.didset (InClassAssistantView.swift:105)
Topic:
UI Frameworks
SubTopic:
UIKit
I am working on a SwiftUI project where I need to dynamically update the UI by adding or removing components based on some event. The challenge is handling complex UI structures efficiently while ensuring smooth animations and state management.
Example Scenario:
I have a screen displaying a list of items.
When a user taps an item, additional details (like a subview or expanded section) should appear dynamically.
If the user taps again, the additional content should disappear.
The UI should animate these changes smoothly without causing unnecessary re-renders.
My Current Approach:
I have tried using @State and if conditions to toggle views, like this:
struct ContentView: View {
@State private var showDetails = false
var body: some View {
VStack {
Button("Toggle Details") {
showDetails.toggle()
}
if showDetails {
Text("Additional Information")
.transition(.slide) // Using animation
}
}
.animation(.easeInOut, value: showDetails)
}
}
However, in complex UI scenarios where multiple components need to be shown/hidden dynamically, this approach is not maintainable and could cause performance issues. I need help with the below questions.
Questions:
State Management: Should I use @State, @Binding, or @ObservedObject for handling dynamic UI updates efficiently?
Best Practices: What are the best practices for structuring SwiftUI views to handle dynamic updates without excessive re-renders?
Performance Optimization: How can I prevent unnecessary recomputations when updating only specific UI sections?
Animations & Transitions: What is the best way to apply animations smoothly while toggling visibility of multiple components?
Advanced Approaches: Are there better techniques using @EnvironmentObject, ViewBuilder, or even GeometryReader for dynamically adjusting UI layouts?
Any insights, code examples, or resources would be greatly appreciated.
I’m currently working on a SwiftUI project and trying to implement a transition effect similar to ZoomTransitions. However, I’ve run into an issue.
When transitioning from Page A to Page B using .navigationTransition(.zoom(sourceID: "world", in: animation)), Page A shrinks as expected, but its background color changes to the default white instead of the color I preset.
I want the background color of Page A to remain consistent with my preset during the entire transition process. Here’s a simplified version of my code:
Page A
PartnerCard()
.matchedTransitionSource(id: item.id, in: animation)
Page B
``.navigationTransition(.zoom(sourceID: "world", in: animation))
Topic:
UI Frameworks
SubTopic:
SwiftUI
on iOS you can choose to scale to view to have the app resize the screen easily in the developer environment. Scale to view is however not easily done on MacOS using NS to solve on MacOS now. Is it possible for the Apple developer team to make this easier for the Developer, as I understand it is for iOS applications?
In the header for UIViewController, the method dismissViewControllerAnimated is declared like this:
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^ __nullable)(void))completion NS_SWIFT_DISABLE_ASYNC API_AVAILABLE(ios(5.0));
NS_SWIFT_DISABLE_ASYNC means that there's no async version exposed like there would normally be of a method that exposes a completion handler. Why is this? And is it unwise / unsafe for me to make my own async version of it using a continuation?
My use case is that I want a method that will sequentially dismiss all view controllers presented by a root view controller. So I could have this extension on UIViewController:
extension UIViewController {
func dismissAsync(animated: Bool) async {
await withCheckedContinuation { continuation in
self.dismiss(animated: animated) {
continuation.resume()
}
}
}
func dismissPresentedViewControllers() async {
while self.topPresentedViewController != self {
await self.topPresentedViewController.dismissAsync(animated: true)
}
}
var topPresentedViewController: UIViewController {
var result = self
while result.presentedViewController != nil {
result = result.presentedViewController!
}
return result
}
Hi,
A class initialized as the initial value of an @State property is not released until the whole View disappears. Every subsequent instance deinitializes properly.
Am I missing something, or is this a known issue?
struct ContentView: View {
// 1 - init first SimpleClass instance
@State var simpleClass: SimpleClass? = SimpleClass(name: "First")
var body: some View {
VStack {
Text("Hello, world!")
}
.task {
try? await Task.sleep(for: .seconds(2))
// 2 - init second SimpleClass instance and set as new @State
// "First" should deinit
simpleClass = SimpleClass(name: "Second")
// 3 - "Second" deinit just fine
simpleClass = nil
}
}
}
class SimpleClass {
let name: String
init(name: String) {
print("init: \(name)")
self.name = name
}
deinit {
print("deinit: \(name)")
}
}
output:
init: First
init: Second
deinit: Second
Thanks
The pitch slider is not supported on tvOS yet it displays when using the Map() view. Does anyone know how to hide it? It's really getting in the way of my UI.
Topic:
UI Frameworks
SubTopic:
SwiftUI
I've encountered an issue where using @Observable in SwiftUI causes extra initializations and deinitializations when a reference type is included as a property inside a struct. Specifically, when I include a reference type (a simple class Empty {}) inside a struct (Test), DetailsViewModel is initialized and deinitialized twice instead of once. If I remove the reference type, the behavior is correct.
This issue does not occur when using @StateObject instead of @Observable. Additionally, I've submitted a feedback report: FB16631081.
Steps to Reproduce
Run the provided SwiftUI sample code (tested on iOS 18.2 & iOS 18.3 using Xcode 16.2).
Observe the console logs when navigating to DetailsView.
Comment out var empty = Empty() in the Test struct.
Run again and compare console logs.
Change @Observable in DetailsViewModel to @StateObject and observe that the issue no longer occurs.
Expected Behavior
The DetailsViewModel should initialize once and deinitialize once, regardless of whether Test contains a reference type.
Actual Behavior
With var empty = Empty() present, DetailsViewModel initializes and deinitializes twice. However, if the reference type is removed, or when using @StateObject, the behavior is correct (one initialization, one deinitialization).
Code Sample
import SwiftUI
enum Route {
case details
}
@MainActor
@Observable
final class NavigationManager {
var path = NavigationPath()
}
struct ContentView: View {
@State private var navigationManager = NavigationManager()
var body: some View {
NavigationStack(path: $navigationManager.path) {
HomeView()
.environment(navigationManager)
}
}
}
final class Empty { }
struct Test {
var empty = Empty() // Comment this out to make it work
}
struct HomeView: View {
private let test = Test()
@Environment(NavigationManager.self) private var navigationManager
var body: some View {
Form {
Button("Go To Details View") {
navigationManager.path.append(Route.details)
}
}
.navigationTitle("Home View")
.navigationDestination(for: Route.self) { route in
switch route {
case .details:
DetailsView()
.environment(navigationManager)
}
}
}
}
@MainActor
@Observable
final class DetailsViewModel {
var fullScreenItem: Item?
init() {
print("DetailsViewModel Init")
}
deinit {
print("DetailsViewModel Deinit")
}
}
struct Item: Identifiable {
let id = UUID()
let value: Int
}
struct DetailsView: View {
@State private var viewModel = DetailsViewModel()
@Environment(NavigationManager.self) private var navigationManager
var body: some View {
ZStack {
Color.green
Button("Show Full Screen Cover") {
viewModel.fullScreenItem = .init(value: 4)
}
}
.navigationTitle("Details View")
.fullScreenCover(item: $viewModel.fullScreenItem) { item in
NavigationStack {
FullScreenView(item: item)
.navigationTitle("Full Screen Item: \(item.value)")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") {
withAnimation(completionCriteria: .logicallyComplete) {
viewModel.fullScreenItem = nil
} completion: {
var transaction = Transaction()
transaction.disablesAnimations = true
withTransaction(transaction) {
navigationManager.path.removeLast()
}
}
}
}
}
}
}
}
}
struct FullScreenView: View {
@Environment(\.dismiss) var dismiss
let item: Item
var body: some View {
ZStack {
Color.red
Text("Full Screen View \(item.value)")
.navigationTitle("Full Screen View")
}
}
}
Console Output
With var empty = Empty() in Test
DetailsViewModel Init
DetailsViewModel Init
DetailsViewModel Deinit
DetailsViewModel Deinit
Without var empty = Empty() in Test
DetailsViewModel Init
DetailsViewModel Deinit
Using @StateObject Instead of @Observable
DetailsViewModel Init
DetailsViewModel Deinit
Additional Notes
This issue occurs only when using @Observable. Switching to @StateObject prevents it. This behavior suggests a possible issue with how SwiftUI handles reference-type properties inside structs when using @Observable.
Using a struct-only approach (removing Empty class) avoids the issue, but that’s not always a practical solution.
Questions for Discussion
Is this expected behavior with @Observable?
Could this be an unintended side effect of SwiftUI’s state management?
Are there any recommended workarounds apart from switching to @StateObject?
Would love to hear if anyone else has run into this or if Apple has provided any guidance!
Before ios18, when two fingers are switched to single fingers, the printing scale value will not change. When switching to two fingers again, the pinch and zoom printing scale will change. The same operation is performed after ios18, and two fingers are switched to single fingers. Switch back to two fingers, and the scale printing will not change.
code here:
- (void)pinchGesture:(UIPinchGestureRecognizer *)recognizer {
NSSet <UIEvent*> *events = [recognizer valueForKey:@"_activeEvents"];
UIEvent *event = [events anyObject];
if (recognizer.state == UIGestureRecognizerStateBegan) {
NSLog(@"---- begin finger count: %d scale: %f",event.allTouches.count,recognizer.scale);
recognizer.scale = 1.0;
} else if (recognizer.state == UIGestureRecognizerStateChanged) {
NSLog(@"---- change finger count: %d scale: %f",event.allTouches.count,recognizer.scale);
// recognizer.scale = 1.0;
}
log image for iOS 17.7
log image for ios18.0.2
I want to get the availableInputs list in widgetextension, but it always returns only the phone's microphone. I have confirmed that I have connected additional Bluetooth devices. Why is this?
If I want to get the information I want, how should I do it?
Topic:
UI Frameworks
SubTopic:
SwiftUI
Hi,
the new style of tab bar is at top, sort of a picker style , how to enforce SwiftUI to use it in old style fashion at bottom in iPadOS same as iOS ?
—
Kind Regards
Topic:
UI Frameworks
SubTopic:
SwiftUI
As you can see in the screenshot, the verification popups that appear when making a StoreKit purchase cut off the buttons. When typing the code into the input field, the window will also flicker and stutter with random view refreshes. Is this something I can configure/change? It's not a very pleasant experience for making an in app purchase.
We've got a hard to repro issue on Intel only when performing UI layout. It seems the collection view code gets into a recursive loop of doom and eventually the app crashes.
This is only happening on Intel, the ARM version is fine. It seems related to this issue: https://developer.apple.com/forums/thread/732580 There an Apple Dev acknowledges that there are issues with the Intel version of the OS.
Here's the simplified stack we're seeing:
-[NSISEngine _coreReplaceMarker:withMarkerPlusDelta:]"
-[NSISEngine constraintDidChangeSuchThatMarker:shouldBeReplacedByMarkerPlusDelta:]",
-[NSISEngine tryToChangeConstraintSuchThatMarker:isReplacedByMarkerPlusDelta:undoHandler:]",
-[NSLayoutConstraint _tryToChangeContainerGeometryWithUndoHandler:]",
-[NSLayoutConstraint _setSymbolicConstant:constant:symbolicConstantMultiplier:]",
-[NSLayoutConstraint setConstant:]",
-[NSView(NSConstraintBasedLayoutInternal) _updateSimpleAutoresizingConstraintsInPlace:forAutoresizingMask:]",
NSViewUpdateConstraintsForFrameChange
-[NSView setFrameSize:]",
-[NSView setFrame:]",
-[NSClipView _updateOverhangSubviewsIfNeeded]",
-[NSClipView _reflectDocumentViewFrameChange]",
-[NSView _postFrameChangeNotification]","
-[NSView setFrameSize:]",
-[NSCollectionView setFrameSize:]",
-[NSView setFrame:]",
NSViewActuallyUpdateFrameFromLayoutEngine",
-[NSView resizeSubviewsWithOldSize:]",
-[NSView setFrameSize:]",
-[NSClipView setFrameSize:]",
-[NSView setFrame:]",
-[NSScrollView _setContentViewFrame:]",
-[NSScrollView tile]",
-[NSScrollView _tileWithoutRecursing]",
-[NSScrollView reflectScrolledClipView:]",
-[NSClipView _reflectDocumentViewFrameChange]_block_invoke",
-[NSClipView _reflectDocumentViewFrameChange]",
-[NSView _postFrameChangeNotification]",
-[NSView setFrameSize:]",
-[NSCollectionView setFrameSize:]",
-[NSView setFrame:]",
-[NSCollectionView _resizeToFitContentAndClipView]",
-[_NSCollectionViewCore setContentSize:]",
-[_NSCollectionViewCore _updateVisibleCellsNow:]"
-[_NSCollectionViewCore _updateVisibleCellsNow:]"
-[_NSCollectionViewCore _updateVisibleCellsNow:]"
-[_NSCollectionViewCore _updateVisibleCellsNow:]"
.
.
It seems to be limited to macOS 13.1 too. Hoping someone might have a clue?
Thanks,
Robert.
Here's a link to the full stack: https://www.icloud.com/notes/076h1RXj4rvv7TzS5ICnvG6vw#NSCollectionView_crash_stack:
Topic:
UI Frameworks
SubTopic:
AppKit
Hi everyone! I'm thrilled to share that I'm conducting a field research as part of my final university project, focused on iOS architecture.
The goal is to dive deeper into the best practices, challenges, and trends in the iOS development world. To make this research truly impactful, I need your help!
If you're an iOS developer, I’d love it if you could take a few minutes to answer a short survey. Your insights and experiences will be invaluable for my research, and I greatly appreciate your
support!
Here is the link:
https://docs.google.com/forms/d/e/1FAIpQLSdf9cacfA7my1hnlazyl7uJraa2oTsQ7dJBWvFtZ_4vbYenRA/viewform?usp=send_form
Thank you so much in advance for helping me out—feel free to share this post with others who might also be interested. Let’s build something amazing together! 💡✨
UITabBarController
|
|
VC_Tab1 --------------------------- VC_Tab2
| |
| |
VC_Tab1_Child VC_Tab2_Child
|
(HeaderView)
|
(MyButton)
The structure of the view controllers and views in the project is as described above.
<case 1>
self.navigationController?.popToRootViewController(animated: false)
tabBarController.selectedIndex = 1
When popToRootViewController(animated: false) is called in VC_Tab1_Child, followed by setting the tab controller’s selectedIndex = 1, the following results are observed:
viewWillAppear(_:), <VC_Tab2_Child>
deinit, <VC_Tab1_Child>
viewDidAppear(_:), <VC_Tab2_Child>
The originally expected results are as follows
viewWillDisappear(_:), <VC_Tab1_Child>
viewDidDisappear(_:), <VC_Tab1_Child>
deinit, <VC_Tab1_Child>
deinit, <HeaderView>
deinit, <MyButton>
headerView.backButton.rx.tap -> Event completed
headerView.backButton.rx.tap -> isDisposed
viewWillAppear(_:), <VC_Tab2_Child>
viewDidAppear(_:), <VC_Tab2_Child>
The HeaderView belonging to VC_Tab1_Child was not deallocated, and the resources associated with that view were also not released. Similarly, VC_Tab1_Child.viewWillDisappear and VC_Tab1_Child.didDisappear were not called.
<case 2>
self.navigationController?.popToRootViewController(animated: false)
DispatchQueue.main.async {
tabBarController.selectedIndex = 1
}
After performing the pop operation as shown in the code and waiting for a short period before testing, the expected results were generally achieved. (However, rarely, the results were similar to those observed when called without async.)”
<case 3>
self.navigationController?.popToRootViewController(animated: false)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
tabBarController.selectedIndex = 1
}
When a sufficient delay was ensured as described above, the expected results were achieved 100% of the time.”
The abnormal behavior is more pronounced in iOS versions prior to 18 and varies depending on the iOS version.
I couldn’t find any documentation explaining the unexpected behavior shown in the results above. What could be the cause? The simulation code is provided below.
https://github.com/linusix/UITabBarController_Test2
I want to visualize the data stored in a DataFrame using various charts (barmark, sectormark, linemark, etc.).
My questions are as follows:
Can a DataFrame be used directly within a chart? If so, could you provide a simple example?
If it cannot be used directly, what is the correct way to use it? Could you provide an example?
Thank you for your help.
Best regards.
I am working on Agora Voice Call and using CallKit to manage incoming and outgoing calls.
Issue:
When I accept a call, CallKit goes behind my app. I want CallKit to remain in front of my app. Please guide me.
I am able to retrieve the text in the input field by doing:
let contextBeforeInput = textDocumentProxy.documentContextBeforeInput ?? ""
let contextAfterInput = textDocumentProxy.documentContextAfterInput ?? ""
let fullText = contextBeforeInput + contextAfterInput
However, when I'm pasting text into the input field, textDocumentProxy.documentContextBeforeInput refuses to return the entire text from the input field but instead only returns the last two sentences.
I have tried this with the input fields in WhatsApp, Signal, and Telegram and it's all the same, so it doesn't seem to be caused by the specific app.
At first I thought it was a limitation imposed by Apple but other third party keyboard extensions such as Grammarly are able to pick up the whole pasted text from the input field, so how are they doing it?
Topic:
UI Frameworks
SubTopic:
UIKit