ReactiveCocoa
ReactiveCocoa provides reactive, declarative extensions to Apple's Cocoa frameworks, built on ReactiveSwift's stream-of-values primitives. It adds UI bindings, control-event signals, Objective-C method interception, and key-value observation wrapped as composable reactive streams for iOS, macOS, watchOS, and tvOS apps.
MITPermissive — free to use in commercial and proprietary software, with attribution.View license →
Production readiness
3/5- Actively maintainedSlower activity (6–12 months)
- No known vulnerabilitiesNot yet scanned
- Clear, usable licenseMIT (permissive)
- Proven adoptionWidely used
- Has documentationDocumentation indexed
Our analysis
A Cocoa-specific layer on top of ReactiveSwift that exposes UIKit/AppKit controls, KVO, and Objective-C dynamism as composable reactive signals and binding targets, enabling declarative two-way bindings via the `<~` operator.
When to use ReactiveCocoa
Use it in Swift Apple-platform apps where you've adopted ReactiveSwift and want a mature FRP approach to wiring UI state, control events, view-model actions, and KVO observation declaratively instead of with delegates and target/action boilerplate.
When not to
Skip it for new projects targeting iOS 13+/modern Swift where Apple's first-party Combine (plus SwiftUI) covers most needs without a third-party dependency, or if your team prefers RxSwift's larger ecosystem. Cross-platform (non-Apple) code can't use it since it depends on Cocoa.
Strengths
- Mature, battle-tested FRP library with a long history on Apple platforms
- Clean separation: ReactiveCocoa handles UI/Cocoa bindings while ReactiveSwift provides the core primitives
- Expressive `<~` binding syntax and built-in lifetime/memory management via `lifetime`
- Handles Objective-C dynamism (method interception, deinit signals) that pure-Swift solutions can't easily replicate
- Supports Carthage, CocoaPods, and SwiftPM across iOS/macOS/watchOS/tvOS
Trade-offs
- Requires learning ReactiveSwift's Signal/SignalProducer/Property distinction, which has a steep curve
- Apple-only; no value outside the Cocoa ecosystem
- Competes with Apple's now-native Combine, shrinking its mindshare for new projects
- Roadmap and release cadence have slowed; the README's ABI-stability plans read as somewhat dated
- Operator-heavy API (`<~`, etc.) can hurt readability for newcomers
Maturity
A long-established, widely-starred (~20k) project with stable releases and multiple package-manager integrations, though development momentum has cooled as Combine and SwiftUI absorbed much of the FRP-on-Apple use case. Best viewed as a mature, maintained option rather than a fast-evolving one.
⚠️ Looking for the Objective-C API?
🎉 Migrating from RAC 4.x?
What is ReactiveSwift?
ReactiveSwift offers composable, declarative and flexible primitives that are built around the grand concept of streams of values over time. These primitives can be used to uniformly represent common Cocoa and generic programming patterns that are fundamentally an act of observation.
For more information about the core primitives, see ReactiveSwift.
What is ReactiveCocoa?
ReactiveCocoa wraps various aspects of Cocoa frameworks with the declarative ReactiveSwift primitives.
UI Bindings
UI components expose
BindingTargets, which accept bindings from any kind of streams of values via the<~operator.// Bind the `name` property of `person` to the text value of an `UILabel`. nameLabel.reactive.text <~ person.nameNote: You'll need to import ReactiveSwift as well to make use of the
<~operator.Controls and User Interactions
Interactive UI components expose
Signals for control events and updates in the control value upon user interactions.A selected set of controls provide a convenience, expressive binding API for
Actions.// Update `allowsCookies` whenever the toggle is flipped. preferences.allowsCookies <~ toggle.reactive.isOnValues // Compute live character counts from the continuous stream of user initiated // changes in the text. textField.reactive.continuousTextValues.map { $0.characters.count } // Trigger `commit` whenever the button is pressed. button.reactive.pressed = CocoaAction(viewModel.commit)Declarative Objective-C Dynamism
Create signals that are sourced by intercepting Objective-C objects, e.g. method call interception and object deinitialization.
// Notify after every time `viewWillAppear(_:)` is called. let appearing = viewController.reactive.trigger(for: #selector(UIViewController.viewWillAppear(_:))) // Observe the lifetime of `object`. object.reactive.lifetime.ended.observeCompleted(doCleanup)Expressive, Safe Key Path Observation
Establish key-value observations in the form of
SignalProducers andDynamicPropertys, and enjoy the inherited composability.// A producer that sends the current value of `keyPath`, followed by // subsequent changes. // // Terminate the KVO observation if the lifetime of `self` ends. let producer = object.reactive.producer(forKeyPath: #keyPath(key)) .take(during: self.reactive.lifetime) // A parameterized property that represents the supplied key path of the // wrapped object. It holds a weak reference to the wrapped object. let property = DynamicProperty<String>(object: person, keyPath: #keyPath(person.name))
But there are still more to be discovered and introduced. Read our in-code documentations and release notes to find out more.
Getting started
ReactiveCocoa supports macOS 10.9+, iOS 8.0+, watchOS 2.0+, and tvOS 9.0+.
Carthage
If you use Carthage to manage your dependencies, simply add
ReactiveCocoa to your Cartfile:
github "ReactiveCocoa/ReactiveCocoa" ~> 10.1
If you use Carthage to build your dependencies, make sure you have added ReactiveCocoa.framework and ReactiveSwift.framework to the "Linked Frameworks and Libraries" section of your target, and have included them in your Carthage framework copying build phase.
CocoaPods
If you use CocoaPods to manage your dependencies, simply add
ReactiveCocoa to your Podfile:
pod 'ReactiveCocoa', '~> 10.1'
Swift Package Manager
If you use Swift Package Manager, simply add ReactiveCocoa as a dependency
of your package in Package.swift:
.package(url: "https://github.com/ReactiveCocoa/ReactiveCocoa.git", branch: "master")
Git submodule
Add the ReactiveCocoa repository as a submodule of your application’s repository.
Run
git submodule update --init --recursivefrom within the ReactiveCocoa folder.Drag and drop
ReactiveCocoa.xcodeprojandCarthage/Checkouts/ReactiveSwift/ReactiveSwift.xcodeprojinto your application’s Xcode project or workspace.On the “General” tab of your application target’s settings, add
ReactiveCocoa.frameworkandReactiveSwift.frameworkto the “Embedded Binaries” section.If your application target does not contain Swift code at all, you should also set the
EMBEDDED_CONTENT_CONTAINS_SWIFTbuild setting to “Yes”.
Have a question?
If you need any help, please visit our GitHub issues or Stack Overflow. Feel free to file an issue if you do not manage to find any solution from the archives.
Release Roadmap
In Development
Plan of Record
ABI stability release
ReactiveCocoa is expected to declare library ABI stability when Swift rolls out resilience support in Swift 5. Until then, ReactiveCocoa will incrementally adopt new language features.