Skip to content

Commit 2a4ffea

Browse files
authored
Merge pull request #642 from ReactiveCocoa/anders/binding-lhs-optional
Permit optional LHS in `<~` bindings.
2 parents b5f7ece + 80d0b8c commit 2a4ffea

File tree

3 files changed

+60
-10
lines changed

3 files changed

+60
-10
lines changed

CHANGELOG.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
# master
22

3+
*Please add new entries at the top.*
34

4-
# 4.0.0-rc.21. Support Swift 4.2 (Xcode 10) (#644, kudos to @ikesyo)
5+
1. `<~` bindings now works with optional left-hand-side operands. (#642, kudos to @andersio and @Ankit-Aggarwal)
56

6-
# 4.0.0-rc.1*Please add new entries at the top.*
7+
```swift
8+
let nilTarget: BindingTarget<Int>? = nil
9+
10+
// This is now a valid binding. Previously required manual
11+
// unwrapping in ReactiveSwift 3.x.
12+
nilTarget <~ notifications.map { $0.count }
13+
```
14+
15+
# 4.0.0-rc.2
16+
17+
1. Support Swift 4.2 (Xcode 10) (#644, kudos to @ikesyo)
18+
19+
# 4.0.0-rc.1
720

821
1. `Lifetime` may now be manually ended using `Lifetime.Token.dispose()`, in addition to the existing when-token-deinitializes semantic. (#641, kudos to @andersio)
922
1. For Swift 4.1 and above, `BindingSource` conformances are required to have `Error` parameterized as exactly `NoError`. As a result, `Signal` and `SignalProducer` are now conditionally `BindingSource`. (#590, kudos to @NachoSoto and @andersio)

Sources/UnidirectionalBinding.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,16 @@ public struct BindingTarget<Value>: BindingTargetProvider {
149149
self.init(on: scheduler, lifetime: lifetime) { [weak object] in object?[keyPath: keyPath] = $0 }
150150
}
151151
}
152+
153+
extension Optional: BindingTargetProvider where Wrapped: BindingTargetProvider {
154+
public typealias Value = Wrapped.Value
155+
156+
public var bindingTarget: BindingTarget<Wrapped.Value> {
157+
switch self {
158+
case let .some(provider):
159+
return provider.bindingTarget
160+
case .none:
161+
return BindingTarget(lifetime: .empty, action: { _ in })
162+
}
163+
}
164+
}

Tests/ReactiveSwiftTests/UnidirectionalBindingSpec.swift

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class UnidirectionalBindingSpec: QuickSpec {
2121
}
2222

2323
describe("closure binding target") {
24-
var target: BindingTarget<Int>!
25-
var optionalTarget: BindingTarget<Int?>!
24+
var target: BindingTarget<Int>?
25+
var optionalTarget: BindingTarget<Int?>?
2626
var value: Int?
2727

2828
beforeEach {
@@ -33,40 +33,57 @@ class UnidirectionalBindingSpec: QuickSpec {
3333

3434
describe("non-optional target") {
3535
it("should pass through the lifetime") {
36-
expect(target.lifetime).to(beIdenticalTo(lifetime))
36+
expect(target!.lifetime).to(beIdenticalTo(lifetime))
3737
}
3838

3939
it("should trigger the supplied setter") {
4040
expect(value).to(beNil())
4141

42-
target.action(1)
42+
target!.action(1)
4343
expect(value) == 1
4444
}
4545

4646
it("should accept bindings from properties") {
4747
expect(value).to(beNil())
4848

4949
let property = MutableProperty(1)
50-
target <~ property
50+
target! <~ property
5151
expect(value) == 1
5252

5353
property.value = 2
5454
expect(value) == 2
5555
}
5656
}
5757

58-
describe("optional target") {
58+
describe("target of optional value") {
5959
it("should pass through the lifetime") {
60-
expect(optionalTarget.lifetime).to(beIdenticalTo(lifetime))
60+
expect(optionalTarget!.lifetime).to(beIdenticalTo(lifetime))
6161
}
6262

6363
it("should trigger the supplied setter") {
6464
expect(value).to(beNil())
6565

66-
optionalTarget.action(1)
66+
optionalTarget!.action(1)
6767
expect(value) == 1
6868
}
6969

70+
it("should accept bindings from properties") {
71+
expect(value).to(beNil())
72+
73+
let property = MutableProperty(1)
74+
optionalTarget! <~ property
75+
expect(value) == 1
76+
77+
property.value = 2
78+
expect(value) == 2
79+
}
80+
}
81+
82+
describe("optional LHS binding with non-nil LHS at runtime") {
83+
it("should pass through the lifetime") {
84+
expect(target.bindingTarget.lifetime).to(beIdenticalTo(lifetime))
85+
}
86+
7087
it("should accept bindings from properties") {
7188
expect(value).to(beNil())
7289

@@ -78,6 +95,13 @@ class UnidirectionalBindingSpec: QuickSpec {
7895
expect(value) == 2
7996
}
8097
}
98+
99+
describe("optional LHS binding with nil LHS at runtime") {
100+
it("should pass through the empty lifetime") {
101+
let nilTarget: BindingTarget<Int>? = nil
102+
expect(nilTarget.bindingTarget.lifetime).to(beIdenticalTo(Lifetime.empty))
103+
}
104+
}
81105
}
82106

83107
describe("key path binding target") {

0 commit comments

Comments
 (0)