Skip to content

Commit d09ff7e

Browse files
authored
Merge branch 'master' into combine-previous
2 parents 99cfe89 + 104ec0b commit d09ff7e

File tree

3 files changed

+31
-38
lines changed

3 files changed

+31
-38
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
1. `combinePrevious` for `Signal` and `SignalProducer` no longer requires an initial value. The first tuple would be emitted as soon as the second value is received by the operator if no initial value is given. (#445, kudos to @andersio)
55

6+
1. Fixed an impedance mismatch in the `Signal` internals that caused heap corruptions. (#449, kudos to @gparker42)
7+
68
1. In Swift 3.2 or later, you may create `BindingTarget` for a key path of a specific object. (#440, kudos to @andersio)
79

810
# 2.0.0-alpha.2

Sources/Signal.swift

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public final class Signal<Value, Error: Swift.Error> {
112112
private var hasDeinitialized: Bool
113113

114114
fileprivate init(_ generator: (Observer) -> Disposable?) {
115-
state = .alive(AliveState())
115+
state = .alive(AliveState(observers: Bag()))
116116

117117
updateLock = Lock.make()
118118
sendLock = Lock.make()
@@ -225,7 +225,9 @@ public final class Signal<Value, Error: Swift.Error> {
225225
updateLock.lock()
226226

227227
if case let .alive(state) = state {
228-
token = state.observers.insert(observer)
228+
var observers = state.observers
229+
token = observers.insert(observer)
230+
self.state = .alive(AliveState(observers: observers))
229231
}
230232

231233
updateLock.unlock()
@@ -250,7 +252,7 @@ public final class Signal<Value, Error: Swift.Error> {
250252
if case let .alive(state) = state {
251253
var observers = state.observers
252254
let observer = observers.remove(using: token)
253-
state.observers = observers
255+
self.state = .alive(AliveState(observers: observers))
254256

255257
var result = OperationResult.none
256258

@@ -450,13 +452,14 @@ public final class Signal<Value, Error: Swift.Error> {
450452
private final class AliveState {
451453
/// The observers of the `Signal`.
452454
///
453-
/// - note: Since `Bag` is a copy-on-write collection, writes can be done safety
454-
/// as long as `updateLock` is acquired.
455-
fileprivate var observers: Bag<Observer>
455+
/// - important: `observer` should not be mutated directly given the layout of
456+
/// `Bag`. Copy the bag, and replace the current `AliveState` with
457+
/// a new one created with the bag instead.
458+
fileprivate let observers: Bag<Observer>
456459

457460
/// Create an alive state.
458-
init() {
459-
self.observers = Bag()
461+
init(observers: Bag<Observer>) {
462+
self.observers = observers
460463
}
461464
}
462465

Sources/UnidirectionalBinding.swift

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -124,53 +124,41 @@ public struct BindingTarget<Value>: BindingTargetProvider {
124124
return self
125125
}
126126

127-
/// Creates a binding target.
127+
/// Creates a binding target which consumes values on the specified scheduler.
128+
///
129+
/// If no scheduler is specified, the binding target would consume the value
130+
/// immediately.
128131
///
129132
/// - parameters:
133+
/// - scheduler: The scheduler on which the `action` consumes the values.
130134
/// - lifetime: The expected lifetime of any bindings towards `self`.
131135
/// - action: The action to consume values.
132-
public init(lifetime: Lifetime, action: @escaping (Value) -> Void) {
133-
self.action = action
136+
public init(on scheduler: Scheduler = ImmediateScheduler(), lifetime: Lifetime, action: @escaping (Value) -> Void) {
134137
self.lifetime = lifetime
135-
}
136138

137-
/// Creates a binding target which consumes values on the specified scheduler.
138-
///
139-
/// - parameters:
140-
/// - scheduler: The scheduler on which the `setter` consumes the values.
141-
/// - lifetime: The expected lifetime of any bindings towards `self`.
142-
/// - action: The action to consume values.
143-
public init(on scheduler: Scheduler, lifetime: Lifetime, action: @escaping (Value) -> Void) {
144-
let setter: (Value) -> Void = { value in
145-
scheduler.schedule {
146-
action(value)
139+
if scheduler is ImmediateScheduler {
140+
self.action = action
141+
} else {
142+
self.action = { value in
143+
scheduler.schedule {
144+
action(value)
145+
}
147146
}
148147
}
149-
self.init(lifetime: lifetime, action: setter)
150148
}
151149

152150
#if swift(>=3.2)
153-
// `Lifetime` is required on these overloads. RAC would provide convenience overloads
154-
// for these with `lifetime(of:)`.
155-
156-
/// Creates a binding target.
157-
///
158-
/// - parameters:
159-
/// - lifetime: The expected lifetime of any bindings towards `self`.
160-
/// - object: The object to consume values.
161-
/// - keyPath: The key path of the object that consumes values.
162-
public init<Object: AnyObject>(lifetime: Lifetime, object: Object, keyPath: ReferenceWritableKeyPath<Object, Value>) {
163-
self.init(lifetime: lifetime) { [weak object] in object?[keyPath: keyPath] = $0 }
164-
}
165-
166151
/// Creates a binding target which consumes values on the specified scheduler.
167152
///
153+
/// If no scheduler is specified, the binding target would consume the value
154+
/// immediately.
155+
///
168156
/// - parameters:
169-
/// - scheduler: The scheduler on which the `setter` consumes the values.
157+
/// - scheduler: The scheduler on which the key path consumes the values.
170158
/// - lifetime: The expected lifetime of any bindings towards `self`.
171159
/// - object: The object to consume values.
172160
/// - keyPath: The key path of the object that consumes values.
173-
public init<Object: AnyObject>(on scheduler: Scheduler, lifetime: Lifetime, object: Object, keyPath: ReferenceWritableKeyPath<Object, Value>) {
161+
public init<Object: AnyObject>(on scheduler: Scheduler = ImmediateScheduler(), lifetime: Lifetime, object: Object, keyPath: ReferenceWritableKeyPath<Object, Value>) {
174162
self.init(on: scheduler, lifetime: lifetime) { [weak object] in object?[keyPath: keyPath] = $0 }
175163
}
176164
#endif

0 commit comments

Comments
 (0)