Post

Replies

Boosts

Views

Activity

Reply to tabViewBottomAccessory AttributeGraph cycles, broken behavior of views participating in cycles
Xcode Version 26.0 (17A324) iOS 26.0 (23A343) Affects both devices (iPhone 16 Pro) and simulator (iPhone 17 Pro) Here's an example that demonstrates how these AttributeGraph: cycle logs are correlated with broken / unexpected behavior of views involved in the cycle. Clicking on the Button to toggle showOptionA doesn't update which "Slider" is displayed: import SwiftUI struct ContentView: View { var body: some View { TabView { Tab("Home", systemImage: "house") { DemoView(prefix: "Home") } Tab("Alerts", systemImage: "bell") { DemoView(prefix: "Alerts") } TabSection("Categories") { Tab("Climate", systemImage: "fan") { DemoView(prefix: "Climate") } Tab("Lights", systemImage: "lightbulb") { DemoView(prefix: "Lights") } } } .tabViewBottomAccessory { MusicPlaybackView() } .tabBarMinimizeBehavior(.onScrollDown) } } struct DemoView: View { let prefix: String var body: some View { List(0..<50, id: \.self) { i in Text("\(prefix) Item #\(i + 1)") } } } struct MusicPlaybackView: View { @Environment(\.tabViewBottomAccessoryPlacement) var placement var body: some View { if placement == .inline { ControlsPlaybackView() } else { SliderPlaybackView() } } } struct ControlsPlaybackView: View { var body: some View { Text("Controls") } } struct SliderPlaybackView: View { @State private var showOptionA = false var body: some View { HStack { if showOptionA { Text("Slider A") } else { Text("Slider B") } Button { showOptionA.toggle() } label: { if showOptionA { Text("Option A") } else { Text("Option B") } } } .animation(.default, value: showOptionA) } } Expected Tapping the button toggles showOptionA and immediately swaps the displayed "Slider". No AttributeGraph cycle warnings. Actual The label fails to update. These errors are logged in the console: === AttributeGraph: cycle detected through attribute 126800 === === AttributeGraph: cycle detected through attribute 29376 === === AttributeGraph: cycle detected through attribute 126800 === === AttributeGraph: cycle detected through attribute 126800 === === AttributeGraph: cycle detected through attribute 126800 === === AttributeGraph: cycle detected through attribute 32488 === === AttributeGraph: cycle detected through attribute 29376 === === AttributeGraph: cycle detected through attribute 32488 === === AttributeGraph: cycle detected through attribute 29376 === === AttributeGraph: cycle detected through attribute 30024 === === AttributeGraph: cycle detected through attribute 29376 === === AttributeGraph: cycle detected through attribute 32488 === === AttributeGraph: cycle detected through attribute 29376 === === AttributeGraph: cycle detected through attribute 30024 === === AttributeGraph: cycle detected through attribute 29376 === === AttributeGraph: cycle detected through attribute 30024 === === AttributeGraph: cycle detected through attribute 29376 === === AttributeGraph: cycle detected through attribute 32488 === === AttributeGraph: cycle detected through attribute 29376 === === AttributeGraph: cycle detected through attribute 32488 === The "Slider" is a placeholder Text element because any use of Slider seems to trigger the same warnings. The same SliderPlaybackView works fine in an .overlay(). Simplifying SliderPlaybackView in this manner seems to avoid the cycles in the tabViewBottomAccessory: struct SliderPlaybackView: View { @State private var showOptionA: Bool = false var body: some View { HStack { Text(showOptionA ? "Slider A" : "Slider B") Text(showOptionA ? "Option A" : "Option B") .onTapGesture { showOptionA.toggle() } } .animation(.default, value: showOptionA) } } The seemingly limited functionality available in tabViewBottomAccessory's Content closure requires a lot of trial and error to discover and significantly increases the level of effort required to adopt this new API.
Topic: UI Frameworks SubTopic: SwiftUI
Sep ’25