NEW Tool! SwiftFairy: Local Swift and SwiftUI code reviews for your coding agent. Learn more ...NEW Tool! SwiftFairy:Local code reviews for your agents. Learn more...
← All SwiftFairy Scrolls

SwiftFairy Scroll

Proper SwiftUI

Correct subtle bugs and performance issues in data flow, state ownership, and view updates by using SwiftUI as it was designed to be used.

What your agent can improve

Data flow

Help your agent trace how data moves between views and resolve issues in how it is shared, so each view receives the data it needs.

State ownership

Give your agent guidance on where state belongs and which view owns it, helping it manage that state throughout the view's lifecycle.

View identity

Identify changes in view identity that can unexpectedly discard state, with guidance and code examples to help your agent preserve it.

View updates and performance

Find dependencies that trigger unnecessary view updates and repeated work, helping your agent improve performance by using SwiftUI as it was designed to be used.

Issues Proper SwiftUI flags

Proper SwiftUI flags over 100 issues in your code. Each finding arrives at the line where the issue occurs, with the guidance and code example written for that case.

  • View helper properties and methods that have no update boundary of their own
  • ForEach rows identified by index, offset, or an editable value
  • Identifiers regenerated on each access or derived from editable properties
  • A view-created model stored outside State or StateObject
  • Side effects and state synchronisation in view initializers
  • Frequently changing values written into the environment
  • Closures and whole structs passed to child views that read only part of them
  • dismiss read or called outside the presented content
  • Lifecycle modifiers attached to a Group or a list of views
  • AnyView and conditional modifiers that hide view identity
Alone SwiftFairy

Token efficiency

Your agent skips millions of tokens of reasoning and reads guidance only for the issues flagged.

Cross-file insight

Follows your view hierarchy across files and presentations, beyond single views and functions.

Deep knowledge

Built on our books and articles, and Natalia's work on Apple's SwiftUI team.

Example findings

These examples show the patterns SwiftFairy flags and the guidance your agent can use to address them. Highlighted lines mark the code to review; each finding indicates whether the guidance is a requirement, recommendation, or consideration.

Must not

Extract computed view builders into views

When we use a helper function or a computed property to return some View, we are simply moving a piece of the parent's body logic to a different location in the same component. This does not give the extracted code independent dependency tracking. When the parent reevaluates its body, the helper's logic runs again, even if the data it uses hasn't changed.

Pattern flagged for review

struct AnimalDetailView: View {
     let animal: Animal

     var body: some View {
         habitatSection
     }

     @ViewBuilder
     private var habitatSection: some View {
         AnimalInfoSection(
             header: "Habitat",
             info: animal.habitatName
         )
     }
}

A possible improvement

// In AnimalDetailView.body:
AnimalHabitatSection(
     habitatName: animal.habitatName
)

struct AnimalHabitatSection: View {
     let habitatName: String

     var body: some View {
         AnimalInfoSection(
             header: "Habitat",
             info: habitatName
         )
     }
}

Extract the section into a separate view struct, passing it only the information it needs to display its contents. When the parent updates, a new instance of AnimalHabitatSection is created. If its habitat name hasn't changed, SwiftUI can skip the execution of its body.

Should not

Avoid a variable number of views in ForEach blocks

When a ForEach inside a list produces a variable number of rows per element, SwiftUI must evaluate its content for each item in the list to determine which rows exist. Filtering the collection beforehand allows rows to be created lazily.

Pattern flagged for review

ForEach(walks) { walk in
     if walk.isShort {
         Text(walk.name)
     }
}

A possible improvement

ForEach(shortWalks) { walk in
     Text(walk.name)
}

Prepare shortWalks when the source data or filter changes. ForEach then receives a collection with known membership and produces exactly one row per element.

…and over 100 other issues.

Put the findings to work

Ask your agent to review a code change or a complete codebase with SwiftFairy. Your agent uses the findings and their accompanying code examples to resolve issues in your code.

How to use SwiftFairy

Try Proper SwiftUI free for one day

Activate your free trial within the app at any time.

Choose lifetime access, a fixed term, or a subscription for this Scroll, or get all four together in a bundle.

Explore the other Scrolls