iOS/Swift Guidelines

Only use these if you’re working on iOS/Swift project.

Creating State and Manager classes

Always be eager to move functionality to classes. There are 2 main types:

  1. State classes -> global view models, they hold UI state
  2. Manager classes -> for working with either system or custom APIs (APIManager is a good example)

Rules for State and Manager classes

  • Use method grouping (see earlier), the first group should be “Lifecycle” and it should have at least the constructor
  • Dependencies to other instances should be passed via constructor and saved to instance variables
  • If we need to observe changes in other classes, use method group “Observing” for it. Use Combine cancellables.
  • Add a class-level comment to describe class purpose

Rules for State classes

  • Typically used to hold UI state, they always inherit from ObservableObject
  • They initialized in the root file and are exposed to entire app through environment object

Rules for Manager classes

  • Be eager about creating purposeful manager classes. For example, if I ask you to observe user’s location, that’s enough of a functionality to deserve its own class, typically suffixed -Manager, for example UserLocationManager.
  • Feel free to pass other classes to this class if it needs to access their data or observe their state (for example, pass AuthState or SettingsStore)

AuthenticatedView

  • App should have a separate AuthenticatedView, a thin wrapper around MainView or something like that.
  • You can put onAppear and other callbacks here, callbacks that should run once user is authenticated.

User defaults keys

  • There must be a struct/enum listing all keys for user defaults.

Standard navigation controls

Use the standard SwiftUI NavigationStack controls for navigation. Do not create custom button views or button styles for standard things like close/dismiss buttons, back buttons, or toolbar items. Use the system-provided patterns (e.g., Button { dismiss() } label: { Image(systemName: "xmark") } for close, standard back button for NavigationStack).

Sheet modals

Any sheet modal UI should always be implemented in its own separate file, not inline in an existing view file.

Auto-focus text fields

When a text field or text view needs auto-focus, use the UIKit-backed AutoFocusTextView (in Whisper/Views/AutoFocusTextView.swift) instead of SwiftUI’s @FocusState. The UIKit approach focuses faster and more reliably. It accepts font, isAutocorrectEnabled, and placeholder parameters to customize per use case.

Reusable UI components

When implementing UI, proactively extract repeated patterns into reusable components. If a pattern appears in more than one place (e.g., placeholder overlays, styled text fields, card layouts), create a shared component. When refactoring something into a reusable component, update all existing instances to use it — don’t leave duplicated code behind.