Swift is a safe language by design, but iOS and macOS projects accumulate debt in optional handling, memory management, and UI state. VibeRails reads your entire codebase and finds the issues that Xcode warnings do not surface.
Swift's type system and memory model provide strong safety guarantees compared to Objective-C, but legacy Swift projects develop their own characteristic forms of technical debt. These issues tend to be architectural rather than syntactic, making them invisible to the compiler and difficult to detect with pattern-matching tools.
Optional handling is Swift's most visible safety feature and its most common source of
shortcuts. The ! force-unwrap operator is used throughout legacy codebases to
bypass optional checks. Some force-unwraps are genuinely safe because the surrounding logic
guarantees a value exists. Others are latent crashes waiting for an edge case the developer
did not anticipate. In Interface Builder-connected outlets, force-unwrapped optionals are
the convention, but a renamed or disconnected outlet produces a crash at runtime with no
compiler warning. Assessing which force-unwraps are safe requires understanding the context
in which each value is produced and consumed.
ARC memory leaks are a persistent problem in Swift projects. Automatic Reference Counting
handles most memory management automatically, but retain cycles between objects that hold
strong references to each other cause memory to leak silently. The classic pattern is a
closure that captures self strongly, creating a cycle between an object and its
own callback. Delegate patterns, notification observers, and Combine subscriptions are all
common sources of retain cycles. These leaks often go unnoticed because they do not cause
crashes, they cause gradual memory growth that only becomes apparent under sustained use.
SwiftUI state management adds a newer layer of complexity. The framework's property wrappers – @State, @Binding, @ObservedObject,
@StateObject, @EnvironmentObject – each have different ownership
semantics and lifecycle behaviour. Using the wrong wrapper causes subtle bugs: a view that
recreates its observed object on every navigation, a state value that resets when the parent
redraws, or an environment object that is missing from the hierarchy at runtime. These issues
are difficult to reproduce consistently and even harder to diagnose from the code alone.
SwiftLint provides configurable style and convention rules for Swift. The Xcode static analyser can detect some memory issues and potential null dereferences. Instruments profiles runtime behaviour to find leaks and performance bottlenecks. But none of these tools can reason about the architectural patterns in a codebase the way a senior iOS developer would.
Consider an app that uses the coordinator pattern for navigation. Each coordinator holds references to child coordinators and the view controllers they manage. When a user navigates back, the parent coordinator is supposed to remove the child, but one code path skips the removal. The child coordinator and its view controller remain in memory, still observing notifications and responding to events. SwiftLint cannot detect this because the code follows all syntactic rules. The static analyser might flag the retain cycle if it is simple enough, but coordinator patterns with multiple indirection layers exceed its tracking capability.
Objective-C bridging is another area where rule-based tools struggle. Many iOS projects
contain a mix of Swift and Objective-C, connected through bridging headers and generated
interfaces. The type mappings between the two languages are not always obvious: an
Objective-C method that returns nil for an error case maps to an implicitly
unwrapped optional in Swift, which will crash if force-unwrapped. A Swift enum with
associated values cannot be used from Objective-C at all, forcing awkward wrapper patterns.
Evaluating whether the bridging layer between Swift and Objective-C is safe requires
understanding both sides of the boundary simultaneously.
Protocol-oriented design patterns add further complexity. Swift encourages protocol extensions and default implementations, but overuse leads to codebases where the actual method being called depends on the static type of the variable, not the runtime type of the object. This dispatch behaviour surprises developers and introduces subtle bugs that only manifest with specific type combinations.
VibeRails performs a full-codebase scan using frontier large language models. Every Swift source file is analysed along with storyboards, XIBs, project configuration, Package.swift or Podfile dependencies, and test targets. The AI reads each file and reasons about its purpose, structure, and relationship to the rest of the project.
For Swift code specifically, the review covers:
weak references, Combine subscription leaks, notification observers that are never removed, timer references that prevent deallocation@MainActor usage, GCD patterns that should be migrated to structured concurrency, thread-unsafe singleton accessEach finding includes the file path, line range, severity level, category, and a detailed description with suggested remediation. Findings are organised into 17 categories so teams can prioritise by area of concern.
Swift's safety features mean that many potential issues are subtle trade-offs rather than
clear-cut bugs. Is that force-unwrap safe because the preceding guard guarantees a value,
or is there an edge case the developer missed? Is the @ObservedObject correct
for this view's position in the hierarchy, or should it be a @StateObject?
VibeRails supports running reviews with two different AI backends – Claude Code and Codex CLI – in sequence. The first pass discovers issues, the second pass verifies them using a different model architecture. When both models independently flag the same retain cycle or state management issue, confidence is high. When they disagree, the finding warrants closer attention from the team during triage.
This cross-validation is particularly valuable for Swift because Apple's frameworks evolve rapidly. Patterns that were best practice two years ago may now have better alternatives, and distinguishing between outdated-but-working code and genuinely problematic code requires current knowledge. Dual-model verification provides two independent assessments of each finding, reducing the chance that framework evolution bias in one model produces false positives.
After triaging findings, VibeRails can dispatch AI agents to implement fixes directly in your
local repository. For Swift projects, this typically means replacing force-unwraps with
guard-let or if-let patterns, adding [weak self] to closures that cause retain
cycles, correcting SwiftUI property wrapper usage, adding nullability annotations to
Objective-C bridging headers, or migrating GCD patterns to Swift Concurrency.
Each fix is generated as a local code change you can inspect, test, and commit or discard. The AI works within the conventions of the existing codebase, matching the project's architectural patterns, naming style, and framework usage.
VibeRails runs as a desktop app with a BYOK model – it orchestrates Claude Code or Codex CLI installations you already have. No code is uploaded to VibeRails servers. AI analysis is sent directly to the provider you configured, billed to your existing subscription. Each licence covers one developer: $19/month (cancel anytime) or $299 lifetime. The free tier includes 5 issues per session to evaluate the workflow.
Vertel over je team en doelen. We reageren met een concreet uitrolplan.