This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: kmp-swift-arc-gc-weak-reference-bridge

KMP Swift-ARC and Kotlin/Native GC Weak Reference Bridge Standard

Prevents catastrophic cross-runtime retain cycles and memory leaks across the Swift ARC and Kotlin/Native tracing GC boundary. Enforces non-capturing closures, weak bridging wrappers, and deterministic lifecycle disposal for bidirectional delegates and flow subscriptions.

Prohibited Anti-Pattern: Bidirectional Strong Retain Cycles Bridging Swift ARC Object Graphs to Kotlin Native GC

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: KMP Swift-ARC and Kotlin/Native GC Weak Reference Bridge Standard - Prevents catastrophic cross-runtime retain cycles and memory leaks across the Swift ARC and Kotlin/Native tracing GC boundary. Enforces non-capturing closures, weak bridging wrappers, and deterministic lifecycle disposal for bidirectional delegates and flow subscriptions.
globs: **/*iosMain*/**/*.kt, **/*appleMain*/**/*.kt, iosApp/**/*.swift, **/*Bridge*.swift
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/kmp-swift-arc-gc-weak-reference-bridge"
---

# KMP Swift-ARC and Kotlin/Native GC Weak Reference Bridge Standard

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Bidirectional Strong Retain Cycles Bridging Swift ARC Object Graphs to Kotlin Native GC

## System Constraints
You are a Principal Mobile Architect specializing in Kotlin Multiplatform and Apple runtime internals. Mandate and enforce deterministic memory safety across the Kotlin/Native GC and Swift ARC interop boundary. Prevent cross-runtime retain cycles where Swift strong references prevent Kotlin GC sweeps and Kotlin GC objects keep Swift ARC instances pinned in memory indefinitely.

## Strict Guidelines
- Engineers MUST ALWAYS wrap Swift-implemented interfaces and protocols stored in Kotlin/Native via `kotlin.native.ref.WeakReference` to break cross-runtime strong retain cycles.
- Engineers MUST NOT pass escaping Swift closures that capture `self` strongly into Kotlin Coroutines, Kotlin Flows, or persistent Kotlin ViewModel delegates.
- Swift consumers of Kotlin ViewModels or Presenters MUST store the Kotlin instance using ARC `strong` only if the Kotlin instance does not maintain an implicit or explicit reverse pointer to the Swift owner.
- Services exposing Kotlin `SharedFlow` or `StateFlow` to Swift MUST mandate an explicit lifecycle subscription token or `Cancellable` that Swift callers invoke in `deinit` or UI dismiss cycles.
- Components NEVER store direct strong references to iOS platform classes (`UIViewController`, `UIView`, `UIApplicationDelegate`) inside KMP singleton or shared companion objects.

## Bad vs Good Implementations
### Kotlin/Native Delegate Bridge: Strong Bridge Ref vs WeakReference Wrapper

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Kotlin/Native retains the Objective-C/Swift instance pointer strongly as a GC root, while Swift retains BridgePresenter via ARC. The Kotlin tracing GC and Swift ARC cannot traverse across runtime boundaries to break the cycle, resulting in an unrecoverable leak.
```kotlin
package com.example.kmp.bridge

interface NativeUiListener {
    fun onDataLoaded(data: String)
}

// ANTI-PATTERN: Holding a direct strong reference to a Swift ARC delegate.
// When Swift ViewController strongly holds BridgePresenter, and
// BridgePresenter holds NativeUiListener (the ViewController), both runtimes
// fail to release the objects, leaking memory permanently.
class BridgePresenter(private val listener: NativeUiListener) {
    fun loadData() {
        val result = "Payload"
        listener.onDataLoaded(result)
    }
}
```

#### Production Standard (Correct)
> **Standard**: Using `kotlin.native.ref.WeakReference` ensures Kotlin/Native GC does not pin the Swift instance in memory. When the Swift ViewController is dismissed, ARC deallocates it immediately, and `weakListener.value` safely evaluates to null.
```kotlin
package com.example.kmp.bridge

import kotlin.native.ref.WeakReference

interface NativeUiListener {
    fun onDataLoaded(data: String)
}

// PRODUCTION FIX: Wrap Swift ARC delegate in Kotlin/Native WeakReference.
// Permits Swift runtime to deallocate the ViewController, leaving the
// weak reference in Kotlin to cleanly evaluate to null without leaking.
class BridgePresenter(listener: NativeUiListener) {
    private val weakListener: WeakReference<NativeUiListener> = WeakReference(listener)

    fun loadData() {
        val result = "Payload"
        weakListener.value?.onDataLoaded(result)
    }

    fun clear() {
        // Explicit cleanup hook for Swift lifecycle deinit
        weakListener.clear()
    }
}
```

### Swift Collector Bridge: Capturing self vs Weak Capture with Cancellation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The Swift closure captures `self` strongly and is passed into the Kotlin runtime. As long as the Kotlin `UserViewModel` retains the observer closure, `UserProfileViewController` cannot be deallocated by ARC upon navigation pop.
```swift
import UIKit
import SharedKit

final class UserProfileViewController: UIViewController {
    private let viewModel = UserViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        // ANTI-PATTERN: Escaping closure captures `self` strongly.
        // If ViewModel holds the closure/cancellable without lifecycle bounding,
        // UserProfileViewController is permanently retained by Kotlin GC.
        viewModel.observeState { state in
            self.updateUI(with: state)
        }
    }

    private func updateUI(with state: UserState) {
        // Update UI components
    }
}
```

#### Production Standard (Correct)
> **Standard**: Swift explicitly captures `[weak self]` in the closure, preventing the Kotlin runtime from owning the Swift ViewController. Retaining and cancelling the `CancellableTask` in `deinit` guarantees deterministic cleanup on both runtimes.
```swift
import UIKit
import SharedKit

final class UserProfileViewController: UIViewController {
    private let viewModel = UserViewModel()
    private var observationTask: SharedKit.CancellableTask?

    override func viewDidLoad() {
        super.viewDidLoad()
        // PRODUCTION FIX: Explicit [weak self] capture + explicit cancellation handle
        observationTask = viewModel.observeState { [weak self] state in
            guard let self = self else { return }
            self.updateUI(with: state)
        }
    }

    deinit {
        // Break subscription cleanly on Swift deallocation
        observationTask?.cancel()
        observationTask = nil
    }

    private func updateUI(with state: UserState) {
        // Update UI components
    }
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: KMP Swift-ARC and Kotlin/Native GC Weak Reference Bridge Standard

KMP Swift-ARC and Kotlin/Native GC Weak Reference Bridge Standard defines an industrial-grade behavioral standard for mobile engineering. Prevents catastrophic cross-runtime retain cycles and memory leaks across the Swift ARC and Kotlin/Native tracing GC boundary. Enforces non-capturing closures, weak bridging wrappers, and deterministic lifecycle disposal for bidirectional delegates and flow subscriptions. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Bidirectional Strong Retain Cycles Bridging Swift ARC Object Graphs to Kotlin Native GC Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftBidirectional Strong Retain Cycles Bridging Swift ARC Object Graphs to Kotlin Native GCCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS wrap Swift-implemented interfaces and protocols stored in Kotlin/Native via `kotlin.native.ref.WeakReference` to break cross-runtime strong retain cycles.

Engineers MUST ALWAYS wrap Swift-implemented interfaces and protocols stored in Kotlin/Native via `kotlin.native.ref.WeakReference` to break cross-runtime strong retain cycles.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT pass escaping Swift closures that capture `self` strongly into Kotlin Coroutines, Kotlin Flows, or persistent Kotlin ViewModel delegates.

Engineers MUST NOT pass escaping Swift closures that capture `self` strongly into Kotlin Coroutines, Kotlin Flows, or persistent Kotlin ViewModel delegates.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Swift consumers of Kotlin ViewModels or Presenters MUST store the Kotlin instance using ARC `strong` only if the Kotlin instance does not maintain an implicit or explicit reverse pointer to the Swift owner.

Swift consumers of Kotlin ViewModels or Presenters MUST store the Kotlin instance using ARC `strong` only if the Kotlin instance does not maintain an implicit or explicit reverse pointer to the Swift owner.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Services exposing Kotlin `SharedFlow` or `StateFlow` to Swift MUST mandate an explicit lifecycle subscription token or `Cancellable` that Swift callers invoke in `deinit` or UI dismiss cycles.

Services exposing Kotlin `SharedFlow` or `StateFlow` to Swift MUST mandate an explicit lifecycle subscription token or `Cancellable` that Swift callers invoke in `deinit` or UI dismiss cycles.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER store direct strong references to iOS platform classes (`UIViewController`, `UIView`, `UIApplicationDelegate`) inside KMP singleton or shared companion objects.

Components NEVER store direct strong references to iOS platform classes (`UIViewController`, `UIView`, `UIApplicationDelegate`) inside KMP singleton or shared companion objects.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is KMP Swift-ARC and Kotlin/Native GC Weak Reference Bridge Standard critical for AI coding assistants?

Prevents catastrophic cross-runtime retain cycles and memory leaks across the Swift ARC and Kotlin/Native tracing GC boundary. Enforces non-capturing closures, weak bridging wrappers, and deterministic lifecycle disposal for bidirectional delegates and flow subscriptions. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Bidirectional Strong Retain Cycles Bridging Swift ARC Object Graphs to Kotlin Native GC) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

Related MOBILE Rules

View all rules →
1 Rule in Stack

KMP