1---2name: uikit-ui-common-setup3description: Use when writing or refactoring UIKit UI in this repo, especially Workflow/ViewController wiring, Controller/View components, SnapKit layout, Workspace/Dflat-driven UI state, Objective-C adapter responders, or app threading boundaries.4---56# UIKit UI Common Setup78## First Pass910- Read nearby app code before introducing a new shape.11- Prefer existing Draw Things / Local Code UIKit patterns over new abstractions.12- Use `rg` / `rg --files` to find matching `Workflow`, `ViewController`, and `Controller` examples.1314## Workflow And ViewController1516- UI screens are managed by `Workflow` objects.17- A `Workflow` owns the concrete `UIViewController`.18- Expose `viewController` when the workflow needs the concrete type, and `viewControllable` as the generic UIKit-facing `UIViewController`.19- `UIViewController` subclasses are views plus UIKit event handling only.20- Do not put business logic, persistence policy, generation logic, networking, model work, or off-main-thread work in a `UIViewController`.21- `UIViewController` sends events out through delegates. The `Workflow` handles them and sets properties back on the view controller.2223## Controller And View2425- For shared business logic outside a workflow, use Controller & View.26- A controller is a plain Swift class, not `NSObject` and not a UIKit subclass.27- It owns one root `UIView` property, usually `let view: UIView`.28- Controllers are usually owned by workflows. Letting a view controller own one is only for lightweight, mostly animation-focused cases.2930## Layout And View Setup3132- Use lazy vars for referenced views. Each lazy var configures that view and self-contained subviews.33- Put hierarchy assembly and cross-view SnapKit constraints inline in `viewDidLoad` or the controller initializer.34- In `viewDidLoad` or the controller initializer, do layout first, then action/delegate hookups.35- Do not create one-off `configureXXX` / `setupXXX` methods for view setup, layout, or action wiring.36- Domain helpers are fine when they express behavior or reusable construction, such as `makeProjectMenu`, `updateSettingsSections`, or `didTapCollapseOrExpand`.3738## One-Way Dataflow3940- Persisted UI state should flow from Dflat / `Workspace` / `workspace.dictionary` observations into UI properties.41- Delegate callbacks should write source-of-truth state or call workflow/controller behavior, not directly mutate unrelated UI state.42- Even `didSet`-driven UI updates should be reached through the owning `Workflow` or real Controller when the state is not purely local view presentation.43- Keep view controllers as render targets: set properties on them; let them update UIKit controls.4445## Objective-C And UIKit Adapters4647- A `UIViewController` already inherits from `NSObject`; using it for UIKit lifecycle/delegates is fine.48- Plain controllers must stay plain Swift classes.49- When a plain controller needs Objective-C delegation, target/action, or UIKit delegate conformance, create a nested responder such as `Controller.ObjCResponder: NSObject`.50- The responder forwards callbacks back to the controller; it does not own business logic.5152## Threads And Queues5354- Do not use `async` / `await` in app UI code.55- `UIViewController` subclasses and views should only touch main-thread UIKit state.56- Workflow and Controller objects are the right places for off-main-thread behavior.57- Avoid creating private queues per workflow/controller. Reuse existing shared queues when behavior fits.58- Prefer one or two shared queues for broad work classes, like Draw Things' edit queue handling generation, tokenization, and related work.59- Create a new queue only when the behavior truly needs a separate serialization or QoS boundary. For rare fire-and-forget work, a global concurrent queue can be acceptable.