Skip to content

ReactiveCocoa/ReactiveObjCBridge

Repository files navigation

ReactiveObjCBridge

After the announcement of Swift, ReactiveCocoa was rewritten in Swift. This framework creates a bridge between those Swift and Objective-C APIs (now known as ReactiveSwift and ReactiveObjC respectively).

Because the APIs are based on fundamentally different designs, the conversion is not always one-to-one; however, every attempt has been made to faithfully translate the concepts between the two APIs (and languages).

The bridged types include:

  1. RACSignal and SignalProducer or Signal
  2. RACCommand and Action
  3. RACScheduler and SchedulerType
  4. RACDisposable and Disposable

For the complete bridging API, including documentation, see ObjectiveCBridging.swift.

RACSignal and SignalProducer or Signal

In ReactiveSwift, “cold” signals are represented by the SignalProducer type, and “hot” signals are represented by the Signal type.

“Cold” RACSignals can be converted into SignalProducers using the SignalProducer initializer:

extension SignalProducer where Error == Swift.Error {
	public init<SignalValue>(_ signal: RACSignal<SignalValue>) where Value == SignalValue?
}

“Hot” RACSignals cannot be directly converted into Signals, because any RACSignal subscription could potentially involve side effects. To obtain a Signal, use RACSignal.toSignalProducer followed by SignalProducer.start, which will make those potential side effects explicit.

For the other direction, use the bridged property.

When invoked on a SignalProducer, these functions will create a RACSignal to start() the producer once for each subscription:

extension SignalProducerProtocol where Value: AnyObject {
	public var bridged: RACSignal<Value>
}

extension SignalProducerProtocol where Value: OptionalProtocol, Value.Wrapped: AnyObject {
	public var bridged: RACSignal<Value.Wrapped>
}

When invoked on a Signal, these methods will create a RACSignal that simply observes it:

extension SignalProtocol where Value: AnyObject {
    public var bridged: RACSignal<Value.Wrapped> {
}

extension SignalProtocol where Value: OptionalProtocol, Value.Wrapped: AnyObject {
    public var bridged: RACSignal<Value.Wrapped> {
}

RACSignals of numbered tuples can be bridged to SignalProducers of Swift tuples with a special initializer, init(bridging:):

extension SignalProducer where Error == Swift.Error {
	public init<First>(bridging tupleSignal: RACSignal<RACOneTuple<First>>) where Value == First?
  public init<First, Second>(bridging tupleSignal: RACSignal<RACTwoTuple<First, Second>>) where Value == (First?, Second?)?
  public init<First, Second, Third>(bridging tupleSignal: RACSignal<RACThreeTuple<First, Second, Third>>) where Value == (First?, Second?, Third?)?
  public init<First, Second, Third, Fourth>(bridging tupleSignal: RACSignal<RACFourTuple<First, Second, Third, Fourth>>) where Value == (First?, Second?, Third?, Fourth?)?
  public init<First, Second, Third, Fourth, Fifth>(bridging tupleSignal: RACSignal<RACFiveTuple<First, Second, Third, Fourth, Fifth>>) where Value == (First?, Second?, Third?, Fourth?, Fifth?)?
}

RACCommand and Action

To convert RACCommands into the new Action type, use the Action initializer:

extension Action where Error == Swift.Error {
	public convenience init<CommandInput, CommandOutput>(
		_ command: RACCommand<CommandInput, CommandOutput>
	) where Input == CommandInput?, Output == CommandOutput?
}

To convert Actions into RACCommands, use the bridged instance method:

extension Action where Input: AnyObject, Output: AnyObject {
	public var bridged: RACCommand<Input, Output>
}

extension Action where Input: OptionalProtocol, Input.Wrapped: AnyObject, Output: AnyObject {
	public var bridged: RACCommand<Input.Wrapped, Output>
}

extension Action where Input: AnyObject, Output: OptionalProtocol, Output.Wrapped: AnyObject {
	public var bridged: RACCommand<Input, Output.Wrapped>
}

extension Action where Input: OptionalProtocol, Input.Wrapped: AnyObject, Output: OptionalProtocol, Output.Wrapped: AnyObject {
	public var bridged: RACCommand<Input.Wrapped, Output.Wrapped>
}

NOTE: The executing properties of actions and commands are not synchronized across the API bridge. To ensure consistency, only observe the executing property from the base object (the one passed into the bridge, not retrieved from it), so updates occur no matter which object is used for execution.

RACScheduler and SchedulerType

Any RACScheduler instance is automatically a DateSchedulerType (and therefore a SchedulerType), and can be passed directly into any function or method that expects one.

All Schedulers and DateSchedulers can be wrapped as a RACScheduler using the RACScheduler initializer:

extension RACScheduler {
	public convenience init(_ scheduler: Scheduler)
	public convenience init(_ scheduler: DateScheduler)
}

Note that wrapped Schedulers would behave like RACImmediateScheduler when deferred scheduling methods are used.

RACDisposable and Disposable

Any RACDisposable instance is automatically a Disposable, and can be used directly anywhere a type conforming to Disposable is expected.

Use the RACDisposable initializer to wrap an instance of Disposable:

extension RACDisposable {
	public convenience init(_ disposable: Disposable?)
}

Numbered RACTuples

Numbered (and typed) RACTuple subtypes, such as RACOneTuple, RACTwoTuple etc., can be bridged to native Swift tuples with a series of global functions:

public func bridgedTuple<First>(from tuple: RACOneTuple<First>) -> (First?)
public func bridgedTuple<First, Second>(from tuple: RACTwoTuple<First, Second>) -> (First?, Second?)
public func bridgedTuple<First, Second, Third>(from tuple: RACThreeTuple<First, Second, Third>) -> (First?, Second?, Third?)
public func bridgedTuple<First, Second, Third, Fourth>(from tuple: RACFourTuple<First, Second, Third, Fourth>) -> (First?, Second?, Third?, Fourth?)
public func bridgedTuple<First, Second, Third, Fourth, Fifth>(from tuple: RACFiveTuple<First, Second, Third, Fourth, Fifth>) -> (First?, Second?, Third?, Fourth?, Fifth?)