SwiftUI: @State and the Attribute Graph
@Stateis one of the many SwiftUI’s pillars that, once understood, we take for granted and use pretty much everywhere without a second thought. But what is@State? What’s happening behind the scenes?
The answer is that
@Statedoes not store its value in the struct. The struct holds only a thin token - a reference to a node in an external, long-lived graph maintained by the SwiftUI runtime.[…]
State in the Attribute Graph is owned by the view that declares it. Lifetime of the graph node is tied to the lifetime of that view’s identity in the hierarchy.
As is generally known, SwiftUI hands off some of its work to a private framework called AttributeGraph. In this article we will explore how SwiftUI uses that framework to efficiently update only those parts of an app necessary and to efficiently get the data out of your view graph it needs for rendering your app.
In this talk, we’ll look at the system that underpins SwiftUI: the attribute graph.
Previously:
- Making Friends With AttributeGraph
- SwiftUI Data Flow 2023
- The SwiftUI Render Loop
- Lifetime of State Properties in SwiftUI
- Gosh Darn SwiftUI
Update (2026-05-15): Mindaugas Rudokas:
For an official “documentation” source, this WWDC video has a segment with pretty good illustrated explanation on how AttributeGraph and update cycle of SwiftUI works (starts at 20:47).
11 Comments RSS · Twitter · Mastodon
Learning Flutter and the whole you bag your state in a state object is very similar. Not sure why anyone who likes this model would pick SwiftUI when you can run Flutter anywhere.
I just shake my head when I look at hundreds of lines of UI spaghetti tied together tightly like shoelaces and you describe everything about your view in a gigantic list. and then...whoops I meant to wrap that in a Column at the top and that causes like an 800 line diff because the entire code underneath indents.
What was the name of that tool that generated XML files that described your UI automatically?
@Objc4Life I believe that tool was called Interface Builder and it was a graphical user interface tool that let you — get this - build graphical user interfaces. But it fell out of favor following the introduction of Swift, because the same people that were scared off by Objective-C's square bracket syntax, now began invading the platform.
Many of these developers didn't want to use Interface Builder for one of two reasons. 1) "Real developers write code! That GUI thing is a toy!" much like the reaction of folks when they saw the original Macintosh. That Mac thing is toy, real computers use DOS, hardcore users write commands!
2) these folks apparently are not qualified or competent enough to merge a simple text based XML file. So the "best practice" became don't use IB with large teams, even though many of the Mac Ass Mac Apps from the glory days (iLife, iWork, etc) had hundreds of Nibs. Imagine that.
‹label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" text="A simple text label " textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0", id="S3j-81-2jc">
Obviously, the XML above is impossible to merge, there's no way to know that we have a UILabel with some text assigned to it and that the text alignment is center, via the human readable XML attributes.
To make matters even worse, it comes with an id value of "S3j-81-2jc" which I can copy and paste into Interface Builder when doing a code review, and IB will highlight the UIView with that particular ID allowing me to visually inspect the UI that I'm PR reviewing. The horrors of reviewing a graphical user interface in its graphical form. And these same Interface Builder views and storyboards also work with Xcode Previews for a "live view". Some folks I see call these SwiftUI previews, even though they work with UIKit as well.
In all seriousness, I started writing an article where I re-wrote SwiftUI code written by many "Swiftluencers" who sell SwiftUI books and Training courses. And in every case I re-wrote their "isn't this incredible" SwiftUI code using UIKit and IB and was able to do it in less lines of code every single time.
All that code to say setup some basic navigation in SwiftUI — using a ForEach, NavigationLink and .navigationDestination() modifiers — none of that code needs to exist with UIKit. You drag and draw a line from one IB Scene to the next in the Storyboard. Literally draw a line.
Ultimately it was taking too much of my time and I just got to the point where I don't give a F anymore about iOS or Apple development in general. On the other hand, the recent post on this blog "Building Shopie for Mac with SwiftUI" and seeing all the negative comments there about SwiftUI in general — has me wondering if I should dust off that article and see it through to completion, as many folks seem to finally be willing to admit that SwiftUI is problematic and not as great nor living up to all the hype when it was introduced.
Much of that hype was amplified by the folks that make their living selling tutorials and books on the topic as well. They are not building enterprise grade apps. Only so much money to be made selling UIKit books when you have a stable and mature framework like that. It was in their best interests to hype it up as well.
Unfortuantely I think modern day Apple has trouble (lack of courage?) in knowing when to cut their losses short.
@Anonymous, at least from my experience, let's be honest and also iterate the numerous issues with Interface Builder in later years:
1. Storyboards seemed to be very fragile. Copying and pasting views around could end up nerfing other things randomly. In my experience it became a game of avoidance - you wouldn't want to change anything as it could randomly break something else.
2. Interface Builder didn't seem to keep up well with the multiple variants that a UI needed to work within: Dynamic Type, Orientation, Appearance modes, Accessibility modes, Size classes and Window screens. It wasn't originally built for such a world, so its support could have been better.
3. Auto Layout sucked. Yes, perhaps if you coded to it directly, but using it within IB was always a horrendous pain.
4. IB's interface was opaque. The dragging of items around, along with how to make connections had become too complex, and lost the simplicity of the gestures that started in the original NeXT IB.
I felt that the original Interface Builder was a great Mac UI builder, but as it grew to also support iOS and became integrated into Xcode, it became less and less reliable.
It doesn't mean that a visual GUI builder couldn't support all of the modern requirements and practices well, but IB as it is today, is not that tool.
@Matthew
I actually think the biggest problem with IB today is storyboards. They encourage you to build large complicated views all in one go and I think that doesn't work well.
1. Storyboards were probably a bad idea that encouraged the bad practice of super-massive view controllers.
2. I think it actually works fine, IB supports light/dark mode just fine and while you have to think a little more to make dynamic type work that isn't any better in SwiftUI (IMO its just as easy to setup a xib that resizes nicely as it is a SwiftUI view that resizes nicely).
Orientation, size classes and window screens are indicators to me that you are trying to put too much into a single xib. Xibs need to be composable and you need to consider whether or not you can even reuse a UI element or if you should build two. For example I wouldn't try and reuse a safari toolbar across Mac/iPadOS and iOS. iOS just works better if you split up the controls into two separate bars.
3. Auto-Layout is great. I use it from IB and don't really have any complaints. Things to avoid include trying to use IB to enable/disable constraints as width's change. Avoid this whenever possible.
4. I don't know what you're doing but I've never struggled to set delegates, outlets, or actions. Perhaps you mean something else?
More generally I think we need to think of IB as a good way to get your initial UI layout state and then you can use code to juggle views around if size changes.
Another thing I've done is have a small medium and wide set of container views in interface builder, each one with multiple container subviews with constraints. Move subviews between appropriate containers as needed. This is analogous to having views move between VStacks and HStacks depending on view width. In both cases the layout/render pass has to remove a view from one subview and move it to another. It's not as though the SwiftUI one isn't doing that, it just hides it.
You can (and I have) used layout constraints that you activate and deactivate based on width, but I find that the activation and deactivation works best in code where I can define custom breakpoints for each view rather than relying on Apple's size classes.
@Benjamin, you are probably right in pointing out that Storyboards are one of the big problems. Once you have large numbers of views/scenes in a Storyboard, that is when I have found it falls apart.
It also compounds the issues noted in point 4 - once you include segue gestures and hosting controllers etc in the Storyboard then the UI did seem to get overly complex.
My guess is also that the developer experience is a lot different for a developer targeting a single platform (e.g. just an iOS app or just a macOS app) than a developer attempting to target multiple platforms (iOS, iPadOS, macOS and tvOS) with as much of a shared UI layer as feasible.
I never think that a write-once run everywhere UI is the best approach; but many modern apps needs to be able to support multiple operating systems while sharing UI code where it makes sense. Classic IB does not support this very well. SwiftUI is better at this, but still falls very short and doesn't deliver what could be a smoother developer experience for these common cases.
> on the other hand, the recent post on this blog "Building Shopie for Mac with SwiftUI" and seeing all the negative comments there about SwiftUI in general — has me wondering if I should dust off that article and see it through to completion,
Do it! The silent majority has been silent for too long!
When I first heard someone describe using Swift UI as "typing xibs" I laughed but it is basically what they are doing.
I'm in this Flutter project now (because if I'm going to be forced to make apps this way, I'm not going to lock my code to Apple platforms). VS Code inserts these comments so you know your 'closing tag' on your widgets:
),
), // LayoutBuilder
), // ConstrainedBox
), // Padding
), // SafeArea
), // GestureDetector
),// etc.
This is a Scaffold nests like three hundred lines of spaghetti. Those comments are added automatically by VS code. Anytime I change it it is a fairly big change because of the whitespace added. So yeah it basically is your xib but it is in Dart instead of XML and you manually type it. Progress.
I'm working on a fairly simple little Flutter app. I can run it in the Web Browser, as a Mac app, an iPhone app, and on Android and everything seems to work. That part is cool. SwiftUI can't do that. IMO Apple without UIKit/Appkit, they have no competitive advantage. They are just copying everyone else and not doing it any better.
@ObjC4Life small request given you're exploring Flutter; Can you do a tear-off inspector / palettes, the way iWork's (and all Mac Apps) inspectors (or Qt-style dockers) used to work?
I'm curious if this is a "too difficult for us" / "we've never seen that sort of UI, aren't all apps a single window?" issue, or a "this absolutely can not be done with Flutter" issue.
To be fair, managing view files in source code was always much better with Xibs than it ever was with Storyboards. I actually always felt like the execution of storyboards in IB, and the concept as a whole, was just underbaked. I avoided them then, and I avoid them (still) now.
@ObjC4Life - Flutter is, well it's what I wrote in the comments on that Sophie article... it's got a very clear parent-child hierarchy. Something about the design is just superior to SwiftUI, which feels way too unstructured. The structure is one of the key issues, and I think that's why I was so stunned when I told ChatGPT to merge SwiftUI into the VueJS api, and everything suddenly made perfect sense. That structure allows you to actually synthesize your ideas out into code, versus spending all this cognitive load on trying to figure out wtf SwiftUI needs/wants.
I'm not a VSCode guy, I typically use IntelliJ for my Flutter projects. It does the commenting thing too, which is so helpful, and is just overall very, very ergonomic. I have really enjoyed working with Flutter in IntelliJ. A lot of people will say JetBrains products are bloated, but Xcode feels so dated in comparison. Xcode still can't even do multiple cursors or other tricks like that!
Bonus - AI services work well against flutter, especially compared to Swift/SwiftUI, just because it's got so much more usage and materials for the models to train on. It's truly night/day, and the end result is really not all that different than what you'd get with Apple's system frameworks. Makes it much easier to ask and learn about best practices and which patterns to use.
Glad to hear you're getting into Flutter.
@Someone - To answer your question, one of the limitations of Flutter is that it can only operate in a single-window mode right now. It's definitely been discussed in the flutter world, not sure where that stands. Avalonia has the same limitation.
- - - -
If Microsoft wasn't so un-trustable, MAUI would probably be a pretty great option for targeting Apple platforms. I do a lot of C#, and I love it for server-side stuff, but I just can't trust MS with interface frameworks. They can't even figure out where Win32, WinForms, WPF, ModernUI actually stand. I think most Win desktop devs are still using WPF.
>these folks apparently are not qualified or competent enough to merge a simple text based XML file.
It's text-based until it isn't. It's random inscrutable IDs, and serialized XML, like _any_ generated code, always ends up being harder for humans to scrutinize than hand-written XML.
>The horrors of reviewing a graphical user interface in its graphical form.
If someone made tooling to generate PNGs of the previous interface and current interface, that would help (although, as has been pointed out, it wouldn't really account for variations: Dark Mode, different widths, right-to-left, …). But such tooling _isn't_ commonplace, and so the alternative would be checking out the code prior to the PR, building it, opening it in IB, then checking out the state _as of_ the PR, building it, opening it in IB, and figuring out if everything is still right.
Nobody is going to do that every single time they get asked to do a review, for every `xib` or `storyboard` that has changed.
Speaking of Flutter, such tooling _sort of_ exists for it, in the form of "goldens". (And I made a library to port some of that idea to WPF.) So if the UI significantly changes, the tests fail, and/or you _see_ that change straight in the PR UI.
But of course with Flutter, or SwiftUI, that isn't even as necessary; you do have a fighting chance of understanding (minor) diffs in the PR.
> MAUI would probably be a pretty great option for targeting Apple platforms.
MAUI was off to a _rough_ start, but has become solid enough by now that we've shipped a big MAUI app.
But on the Mac? Unlike its predecessor Xamarin Forms, MAUI uses Catalyst on the Mac, not AppKit, and that comes with all kinds of weird limitations. You want a _radio button_? We've never heard of such a thing! To be fair, I haven't tried it in a few years. But when I did, the default look of a MAUI app on macOS was _rough_.
If you want to use a similar stack, Avalonia may be a better choice for Windows+macOS, not so much for mobile. Honestly, if you want iOS, Android, and then secondarily Windows, macOS, Flutter is probably still a good bet.
>They can't even figure out where Win32, WinForms, WPF, ModernUI actually stand.
I could rant on and on about how they haven't had a good strategy here for two decades. WPF is still what I would recommend. (Fortunately, the tech stack is similar enough that it isn't even that hard to switch between WPF, UWP, WinUI 3, MAUI, Avalonia, Uno, …. It's all .NET/C#/XAML.)
> But of course with Flutter, or SwiftUI, that isn't even as necessary; you do have a fighting chance of understanding (minor) diffs in the PR.
I'm skeptical of this being so much better but the format for something like a xib could be made to make it easier to review. The tradeoff is I don't have to type all that UI code, can easily observe the UI visually. Of course there are some parts of the UI that ultimately will need to be done in code but IB still can be a very valuable tool. Wrong way.
The thing with Storyboard as some already touched on is they can grow too big and that can be hard to review but just don't do that. Break it up. You can use one storyboard or xib per view controller, if you want.
> Can you do a tear-off inspector / palettes, the way iWork's (and all Mac Apps) inspectors (or Qt-style dockers) used to work?
I don't think by default. As @Ben wrote the template just generates a single window app. You get an AppDelegate that inherits from FlutterAppDelegate with one window. But you can easily modify your AppDelegate to add multi window support. It looks like there are some packages that add this https://pub.dev/packages/desktop_multi_window but tear off inspectors/palettes it looks like you would have some work to do.
On a positive note I was surprised to see that Flutter has pretty good keyboard navigation support. I figured it would just be lazy mobile port but using the Escape key dismisses sheets, tabbing to focus on buttons and using the return key to press the focused one works. You can do this to make a selection in a "table view" too. That's good.