Skip to content

Commit 5b643a6

Browse files
authored
Merge pull request #25 from erwald/tuple-bridging
Tuple bridging
2 parents be200d6 + 6f61cb7 commit 5b643a6

File tree

7 files changed

+279
-13
lines changed

7 files changed

+279
-13
lines changed

Cartfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
github "ReactiveCocoa/ReactiveObjC" ~> 2.1.2
1+
github "ReactiveCocoa/ReactiveObjC" ~> 3.0.0
22
github "ReactiveCocoa/ReactiveSwift" ~> 1.1

Cartfile.resolved

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
github "Quick/Nimble" "8116a83864ee78339798c3ef425c42f6ca6bf034"
22
github "Quick/Quick" "v1.1.0"
3-
github "ReactiveCocoa/ReactiveObjC" "2.1.2"
4-
github "ReactiveCocoa/ReactiveSwift" "1.1.1"
3+
github "ReactiveCocoa/ReactiveObjC" "3.0.0"
54
github "antitypical/Result" "3.2.1"
65
github "jspahrsummers/xcconfigs" "3d9d99634cae6d586e272543d527681283b33eb0"
6+
github "ReactiveCocoa/ReactiveSwift" "1.1.2"

Carthage/Checkouts/ReactiveObjC

ReactiveObjCBridge.podspec

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Pod::Spec.new do |s|
44
s.summary = "Bridge between ReactiveObjC and ReactiveSwift"
55
s.description = <<-DESC
66
After announced Swift, ReactiveCocoa was rewritten in Swift. This framework creates a bridge between those Swift and Objective-C APIs (ReactiveSwift and ReactiveObjC).
7-
7+
88
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).
99
DESC
1010
s.homepage = "https://github.com/ReactiveCocoa/ReactiveObjCBridge"
@@ -19,7 +19,7 @@ Pod::Spec.new do |s|
1919
s.source = { :git => "https://github.com/ReactiveCocoa/ReactiveObjCBridge.git", :tag => "#{s.version}" }
2020
s.source_files = "ReactiveObjCBridge/*.{swift}"
2121

22-
s.dependency 'ReactiveObjC', '~> 2.1.2'
22+
s.dependency 'ReactiveObjC', '~> 3.0.0'
2323
s.dependency 'ReactiveSwift', '~> 1.1'
2424

2525
s.pod_target_xcconfig = { "OTHER_SWIFT_FLAGS[config=Release]" => "-suppress-warnings" }

ReactiveObjCBridge/ObjectiveCBridging.swift

+122
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ private func defaultNSError(_ message: String, file: String, line: Int) -> NSErr
120120
///
121121
/// - returns: Signal producer created from the provided signal.
122122
public func bridgedSignalProducer<Value>(from signal: RACSignal<Value>, file: String = #file, line: Int = #line) -> SignalProducer<Value?, AnyError> {
123+
return _bridgedSignalProducer(from: signal, file: file, line: line)
124+
}
125+
126+
private func _bridgedSignalProducer<Value>(from signal: RACSignal<Value>, file: String = #file, line: Int = #line) -> SignalProducer<Value?, AnyError> {
123127
return SignalProducer<Value?, AnyError> { observer, disposable in
124128
let next: (_ value: Value?) -> Void = { obj in
125129
observer.send(value: obj)
@@ -137,6 +141,71 @@ public func bridgedSignalProducer<Value>(from signal: RACSignal<Value>, file: St
137141
}
138142
}
139143

144+
/// Create a `SignalProducer` of 1-tuples which will subscribe to the provided
145+
/// signal once for each invocation of `start()`.
146+
///
147+
/// - parameters:
148+
/// - signal: The signal of `RACOneTuple` objects to bridge to a signal producer of 1-tuples.
149+
/// - file: Current file name.
150+
/// - line: Current line in file.
151+
///
152+
/// - returns: Signal producer created from the provided signal.
153+
public func bridgedSignalProducer<First>(from signal: RACSignal<RACOneTuple<First>>, file: String = #file, line: Int = #line) -> SignalProducer<(First?)?, AnyError> {
154+
return _bridgedSignalProducer(from: signal, file: file, line: line).map { $0.map(bridgedTuple) }
155+
}
156+
157+
/// Create a `SignalProducer` of 2-tuples which will subscribe to the provided
158+
/// signal once for each invocation of `start()`.
159+
///
160+
/// - parameters:
161+
/// - signal: The signal of `RACTwoTuple` objects to bridge to a signal producer of 2-tuples.
162+
/// - file: Current file name.
163+
/// - line: Current line in file.
164+
///
165+
/// - returns: Signal producer created from the provided signal.
166+
public func bridgedSignalProducer<First, Second>(from signal: RACSignal<RACTwoTuple<First, Second>>, file: String = #file, line: Int = #line) -> SignalProducer<(First?, Second?)?, AnyError> {
167+
return _bridgedSignalProducer(from: signal, file: file, line: line).map { $0.map(bridgedTuple) }
168+
}
169+
170+
/// Create a `SignalProducer` of 3-tuples which will subscribe to the provided
171+
/// signal once for each invocation of `start()`.
172+
///
173+
/// - parameters:
174+
/// - signal: The signal of `RACThreeTuple` objects to bridge to a signal producer of 3-tuples.
175+
/// - file: Current file name.
176+
/// - line: Current line in file.
177+
///
178+
/// - returns: Signal producer created from the provided signal.
179+
public func bridgedSignalProducer<First, Second, Third>(from signal: RACSignal<RACThreeTuple<First, Second, Third>>, file: String = #file, line: Int = #line) -> SignalProducer<(First?, Second?, Third?)?, AnyError> {
180+
return _bridgedSignalProducer(from: signal, file: file, line: line).map { $0.map(bridgedTuple) }
181+
}
182+
183+
/// Create a `SignalProducer` of 4-tuples which will subscribe to the provided
184+
/// signal once for each invocation of `start()`.
185+
///
186+
/// - parameters:
187+
/// - signal: The signal of `RACFourTuple` objects to bridge to a signal producer of 4-tuples.
188+
/// - file: Current file name.
189+
/// - line: Current line in file.
190+
///
191+
/// - returns: Signal producer created from the provided signal.
192+
public func bridgedSignalProducer<First, Second, Third, Fourth>(from signal: RACSignal<RACFourTuple<First, Second, Third, Fourth>>, file: String = #file, line: Int = #line) -> SignalProducer<(First?, Second?, Third?, Fourth?)?, AnyError> {
193+
return _bridgedSignalProducer(from: signal, file: file, line: line).map { $0.map(bridgedTuple) }
194+
}
195+
196+
/// Create a `SignalProducer` of 5-tuples which will subscribe to the provided
197+
/// signal once for each invocation of `start()`.
198+
///
199+
/// - parameters:
200+
/// - signal: The signal of `RACFiveTuple` objects to bridge to a signal producer of 5-tuples.
201+
/// - file: Current file name.
202+
/// - line: Current line in file.
203+
///
204+
/// - returns: Signal producer created from the provided signal.
205+
public func bridgedSignalProducer<First, Second, Third, Fourth, Fifth>(from signal: RACSignal<RACFiveTuple<First, Second, Third, Fourth, Fifth>>, file: String = #file, line: Int = #line) -> SignalProducer<(First?, Second?, Third?, Fourth?, Fifth?)?, AnyError> {
206+
return _bridgedSignalProducer(from: signal, file: file, line: line).map { $0.map(bridgedTuple) }
207+
}
208+
140209
extension SignalProducerProtocol where Value: AnyObject {
141210
/// Create a `RACSignal` that will `start()` the producer once for each
142211
/// subscription.
@@ -275,6 +344,7 @@ extension ActionProtocol {
275344
/// is.
276345
///
277346
/// - parameters:
347+
/// - command: The command to bridge to an action.
278348
/// - file: Current file name.
279349
/// - line: Current line in file.
280350
///
@@ -360,6 +430,58 @@ extension ActionProtocol where Input: OptionalProtocol, Input.Wrapped: AnyObject
360430
}
361431
}
362432

433+
// MARK: Tuples
434+
435+
/// Creates a Swift tuple with one element.
436+
///
437+
/// - parameters:
438+
/// - tuple: The `RACOneTuple` to bridge to a Swift tuple.
439+
///
440+
/// - returns: Swift tuple created from the provided `RACOneTuple` object.
441+
public func bridgedTuple<First>(from tuple: RACOneTuple<First>) -> (First?) {
442+
return (tuple.first)
443+
}
444+
445+
/// Creates a Swift tuple with two elements.
446+
///
447+
/// - parameters:
448+
/// - tuple: The `RACTwoTuple` to bridge to a Swift tuple.
449+
///
450+
/// - returns: Swift tuple created from the provided `RACTwoTuple` object.
451+
public func bridgedTuple<First, Second>(from tuple: RACTwoTuple<First, Second>) -> (First?, Second?) {
452+
return (tuple.first, tuple.second)
453+
}
454+
455+
/// Creates a Swift tuple with three elements.
456+
///
457+
/// - parameters:
458+
/// - tuple: The `RACThreeTuple` to bridge to a Swift tuple.
459+
///
460+
/// - returns: Swift tuple created from the provided `RACThreeTuple` object.
461+
public func bridgedTuple<First, Second, Third>(from tuple: RACThreeTuple<First, Second, Third>) -> (First?, Second?, Third?) {
462+
return (tuple.first, tuple.second, tuple.third)
463+
}
464+
465+
/// Creates a Swift tuple with four elements.
466+
///
467+
/// - parameters:
468+
/// - tuple: The `RACFourTuple` to bridge to a Swift tuple.
469+
///
470+
/// - returns: Swift tuple created from the provided `RACFourTuple` object.
471+
public func bridgedTuple<First, Second, Third, Fourth>(from tuple: RACFourTuple<First, Second, Third, Fourth>) -> (First?, Second?, Third?, Fourth?) {
472+
return (tuple.first, tuple.second, tuple.third, tuple.fourth)
473+
}
474+
475+
/// Creates a Swift tuple with five elements.
476+
///
477+
/// - parameters:
478+
/// - tuple: The `RACFiveTuple` to bridge to a Swift tuple.
479+
///
480+
/// - returns: Swift tuple created from the provided `RACFiveTuple` object.
481+
public func bridgedTuple<First, Second, Third, Fourth, Fifth>(from tuple: RACFiveTuple<First, Second, Third, Fourth, Fifth>) -> (First?, Second?, Third?, Fourth?, Fifth?) {
482+
return (tuple.first, tuple.second, tuple.third, tuple.fourth, tuple.fifth)
483+
}
484+
363485
// MARK: - Helpers
364486

365487
extension DispatchTimeInterval {

ReactiveObjCBridgeTests/ObjectiveCBridgingSpec.swift

+150-6
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ class ObjectiveCBridgingSpec: QuickSpec {
211211
var command: RACCommand<NSNumber, NSNumber>!
212212
var results: [Int] = []
213213

214-
var enabledSubject: RACSubject!
214+
var enabledSubject: RACSubject<NSNumber>!
215215
var enabled = false
216216

217217
var action: Action<NSNumber?, NSNumber?, AnyError>!
@@ -220,9 +220,9 @@ class ObjectiveCBridgingSpec: QuickSpec {
220220
enabledSubject = RACSubject()
221221
results = []
222222

223-
let enabledSignal = RACSignal<NSNumber>.createSignal({ subscriber in
223+
let enabledSignal = RACSignal<NSNumber>.createSignal { subscriber in
224224
return enabledSubject.subscribe(subscriber)
225-
})
225+
}
226226

227227
command = RACCommand<NSNumber, NSNumber>(enabled: enabledSignal) { input in
228228
let inputNumber = input as! Int + 1
@@ -369,12 +369,12 @@ class ObjectiveCBridgingSpec: QuickSpec {
369369
var action: Action<Optional<AnyObject>, NSString, TestError>!
370370
var command: RACCommand<AnyObject, NSString>!
371371

372-
let inputSubject = RACSubject()
372+
let inputSubject = RACSubject<AnyObject>()
373373

374374
let inputSignal = RACSignal<NSNumber>
375-
.createSignal({ subscriber in
375+
.createSignal { subscriber in
376376
return inputSubject.subscribe(subscriber)
377-
})
377+
}
378378
.replay()
379379
.materialize()
380380

@@ -406,5 +406,149 @@ class ObjectiveCBridgingSpec: QuickSpec {
406406
expect(value).to(beNil())
407407
}
408408
}
409+
410+
context("re tuples") {
411+
describe("bridgedTuple") {
412+
it("should bridge 1-tuples") {
413+
let racTuple = RACOneTuple<NSNumber>.pack(0)
414+
let tuple = bridgedTuple(from: racTuple)
415+
416+
expect(tuple) == (0)
417+
}
418+
419+
it("should bridge 2-tuples") {
420+
let racTuple = RACTwoTuple<NSNumber, NSNumber>.pack(0, 1)
421+
let tuple = bridgedTuple(from: racTuple)
422+
423+
expect(Mirror(reflecting: tuple).children.count) == 2
424+
expect(tuple.0) == 0
425+
expect(tuple.1) == 1
426+
}
427+
428+
it("should bridge 3-tuples") {
429+
let racTuple = RACThreeTuple<NSNumber, NSNumber, NSNumber>.pack(0, 1, 2)
430+
let tuple = bridgedTuple(from: racTuple)
431+
432+
expect(Mirror(reflecting: tuple).children.count) == 3
433+
expect(tuple.0) == 0
434+
expect(tuple.1) == 1
435+
expect(tuple.2) == 2
436+
}
437+
438+
it("should bridge 4-tuples") {
439+
let racTuple = RACFourTuple<NSNumber, NSNumber, NSNumber, NSNumber>.pack(0, 1, 2, 3)
440+
let tuple = bridgedTuple(from: racTuple)
441+
442+
expect(Mirror(reflecting: tuple).children.count) == 4
443+
expect(tuple.0) == 0
444+
expect(tuple.1) == 1
445+
expect(tuple.2) == 2
446+
expect(tuple.3) == 3
447+
}
448+
449+
it("should bridge 5-tuples") {
450+
let racTuple = RACFiveTuple<NSNumber, NSNumber, NSNumber, NSNumber, NSNumber>.pack(0, 1, 2, 3, 4)
451+
let tuple = bridgedTuple(from: racTuple)
452+
453+
expect(Mirror(reflecting: tuple).children.count) == 5
454+
expect(tuple.0) == 0
455+
expect(tuple.1) == 1
456+
expect(tuple.2) == 2
457+
expect(tuple.3) == 3
458+
expect(tuple.4) == 4
459+
}
460+
461+
it("should bridge tuples containing nils") {
462+
let racTuple = RACThreeTuple<NSString, NSString, NSString>.pack(nil, nil, nil)
463+
let tuple = bridgedTuple(from: racTuple)
464+
465+
expect(Mirror(reflecting: tuple).children.count) == 3
466+
expect(tuple.0).to(beNil())
467+
expect(tuple.1).to(beNil())
468+
expect(tuple.2).to(beNil())
469+
}
470+
471+
it("should bridge tuples containing both nils and values") {
472+
let racTuple = RACThreeTuple<NSString, NSString, NSString>.pack("rose", nil, "petal")
473+
let tuple = bridgedTuple(from: racTuple)
474+
475+
expect(Mirror(reflecting: tuple).children.count) == 3
476+
expect(tuple.0) == "rose"
477+
expect(tuple.1).to(beNil())
478+
expect(tuple.2) == "petal"
479+
}
480+
}
481+
482+
describe("bridgedSignalProducer") {
483+
it("should bridge signals of 1-tuples") {
484+
let racSignal = RACSignal<RACOneTuple<NSNumber>>.return(RACOneTuple<NSNumber>.pack(0))
485+
let producer = bridgedSignalProducer(from: racSignal)
486+
487+
let value = producer.single()?.value as? (Int) ?? nil
488+
expect(value) == (0)
489+
}
490+
491+
it("should bridge signals of 2-tuples") {
492+
let racSignal = RACSignal<RACTwoTuple<NSNumber, NSNumber>>.return(RACTwoTuple<NSNumber, NSNumber>.pack(0, 1))
493+
let producer = bridgedSignalProducer(from: racSignal)
494+
495+
let value = producer.single()?.value ?? nil
496+
let valueMirror = value.map { Mirror(reflecting: $0) }
497+
expect(valueMirror?.children.count) == 2
498+
expect(value?.0) == 0
499+
expect(value?.1) == 1
500+
}
501+
502+
it("should bridge signals of 3-tuples") {
503+
let racSignal = RACSignal<RACThreeTuple<NSNumber, NSNumber, NSNumber>>.return(RACThreeTuple<NSNumber, NSNumber, NSNumber>.pack(0, 1, 2))
504+
let producer = bridgedSignalProducer(from: racSignal).skipNil()
505+
506+
let value = producer.single()?.value ?? nil
507+
let valueMirror = value.map { Mirror(reflecting: $0) }
508+
expect(valueMirror?.children.count) == 3
509+
expect(value?.0) == 0
510+
expect(value?.1) == 1
511+
expect(value?.2) == 2
512+
}
513+
514+
it("should bridge signals of 4-tuples") {
515+
let racSignal = RACSignal<RACFourTuple<NSNumber, NSNumber, NSNumber, NSNumber>>.return(RACFourTuple<NSNumber, NSNumber, NSNumber, NSNumber>.pack(0, 1, 2, 3))
516+
let producer = bridgedSignalProducer(from: racSignal).skipNil()
517+
518+
let value = producer.single()?.value ?? nil
519+
let valueMirror = value.map { Mirror(reflecting: $0) }
520+
expect(valueMirror?.children.count) == 4
521+
expect(value?.0) == 0
522+
expect(value?.1) == 1
523+
expect(value?.2) == 2
524+
expect(value?.3) == 3
525+
}
526+
527+
it("should bridge signals of 5-tuples") {
528+
let racSignal = RACSignal<RACFiveTuple<NSNumber, NSNumber, NSNumber, NSNumber, NSNumber>>.return(RACFiveTuple<NSNumber, NSNumber, NSNumber, NSNumber, NSNumber>.pack(0, 1, 2, 3, 4))
529+
let producer = bridgedSignalProducer(from: racSignal).skipNil()
530+
531+
let value = producer.single()?.value ?? nil
532+
let valueMirror = value.map { Mirror(reflecting: $0) }
533+
expect(valueMirror?.children.count) == 5
534+
expect(value?.0) == 0
535+
expect(value?.1) == 1
536+
expect(value?.2) == 2
537+
expect(value?.3) == 3
538+
expect(value?.4) == 4
539+
}
540+
541+
it("should bridge signals of unnumbered tuples") {
542+
let racSignal = RACSignal<RACTuple>.return(RACTuple(objectsFrom: [0, 1]))
543+
let producer = bridgedSignalProducer(from: racSignal).skipNil()
544+
545+
let value = producer.single()?.value
546+
expect(value?.count) == 2
547+
expect(value?.first as? Int) == 0
548+
expect(value?.second as? Int) == 1
549+
expect(value?.third).to(beNil())
550+
}
551+
}
552+
}
409553
}
410554
}

0 commit comments

Comments
 (0)