SwiftUI's Purple Warning Isn't Cosmetic. 'Publishing Changes From Within View Updates' Means You Raced Your Own Render.
Xcode's console warns 'Publishing changes from within view updates is not allowed, this will cause undefined behavior' and most developers just scroll past it. Here's what SwiftUI is actually telling you, the three common ways you trigger it, and why ignoring it eventually costs you a view that won't stop re-rendering.
Weak Self Isn't the Retain Cycle Fix You Think It Is in @Observable
The old [weak self] advice was written for closures capturing classes. @Observable changes what actually gets captured, and in a few common SwiftUI patterns weak self silently does nothing at all. Here's where it still matters and where it's dead weight.
@Observable vs ObservableObject: What 1,000 Rows and a Redraw Counter Actually Showed Me
Day 13 of the 30-day iOS series. I built a redraw counter into BrewLog, put 1,000 rows in two identical lists side by side — one backed by @Observable, one by ObservableObject — and toggled a single favorite ten times. The row counts tied 10-10. The list counts didn't. Here's the real number, and exactly where it comes from.
@State, @Bindable, @Environment: The Complete Map for @Observable (and the Question You're Actually Asking)
Day 12 of the 30-day iOS series. With @Observable, SwiftUI lets you slap @State, @Bindable, @Environment, or a plain let on the same class — and compiles all of them. Here's the question that actually decides which one is correct, one map that resolves 95% of the confusion, and three real BrewLog bugs (one silent, one a compile error, one a runtime crash) that come from picking wrong.
ObservableObject → @Observable: The Migration Guide That Skips the Marketing (and the Autoclosure Gotcha Apple Forgot to Mention)
Day 11 of the 30-day iOS series. Apple's migration guide makes ObservableObject → @Observable look like a find-and-replace. It mostly is — except for one quiet behavioral change: @StateObject only ran your initializer once, and @State runs it on every render. Here's the multiple-init bug that causes, why it's worst in exactly the init you were proud of, and how to fix it with a test that turns 'no side effects in init' into a hard, green invariant.