Adding Event Emitters to Your TurboModule in Swift

TurboModules don’t just expose functions, they can also push information from native to JavaScript. In this episode, Oskar shows how to extend the Local Storage TurboModule from Episode 1 with an event emitter that notifies JS whenever a new key is added. You’ll see how event types flow from TypeScript through Codegen into Objective‑C and Swift, and how to wire everything so JavaScript can subscribe safely and respond in real time.
Adding event types to the TypeScript spec
Oskar introduces the idea of emitting events when native state changes, such as when a new key is added in Local Storage. He adds an event payload type (key, value) and a new Codegen event field. After rerunning Codegen, new interfaces become available on the native side.
Understanding the newly generated native interfaces
Codegen now outputs a NativeLocalStorageSpecBase interface containing the auto‑generated emitOnKeyAdded method. Oskar shows how this sits alongside the existing TurboModule protocol and explains why the module must now inherit from this new base.
Implementing event emission in Swift
The Swift class gains a stored callback (onKeyAdded) and a custom initializer that accepts this closure. Oskar walks through marking the closure @escaping, storing it, and triggering it inside setItem only when a new key is created.
Wiring the Objective‑C Layer
Because the Swift initializer changed, the Objective‑C class must now call initOnKeyAdded: and forward the emitted dictionary back to JS via the generated emitOnKeyAdded. Oskar fills in the placeholders and validates that compilation succeeds.
Avoiding retain cycles
Oskar highlights a subtle memory bug caused by the Swift closure capturing self strongly, while Objective‑C also retains the Swift instance, forming a retain cycle. He fixes it by using a weak reference, breaking the circular ownership.
Subscribing to events in JavaScript
On the JS side, a useEffect subscription listens for onKeyAdded events and shows an alert when they occur. A new button writes a random key to trigger the event, and Oskar verifies the flow step‑by‑step in the Xcode debugger.
Resources
- Oskar Kwaśniewski on X and GitHub
- Other episodes in this series
- Tools & libraries:
- TurboModules (New Architecture)
- Codegen
- Swift + Objective‑C integration
- Expo (testing)
Learn more about React Native
Stay up to date with our latest insights on React, React Native, and cross-platform development from the people who build the technology and scale with it daily.
Learn more about React Native

React Native Wrapped 2025: A Month-by-Month Recap of The Year
The first edition of React Native Wrapped looks back at the year RN turned 10 and the ecosystem doubled down on the New Architecture. It provides a month-by-month record of 2025, covering major framework releases, the Legacy Architecture freeze, React 19 integration, and notable developments across tooling, performance, styling, native modules, Expo, and platform adoption.

Building v0 iOS and Fixing React Native Along the Way
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

Shipping iOS Live Activities with React: The Voltra Story
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

Scaling React Native at Zalando: How Brownfield Migration Paid Off
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.












