Skip to content

Commit 4c981de

Browse files
committed
1.0.5 - Observer Locking Bug Fixed
Fixe for `ObservableThread` and `ObservableThreadSafeClass` whereby items in the pending queues would never be removed, and would never be added due to a foolish mistake of mine.
1 parent 69e9f20 commit 4c981de

File tree

2 files changed

+46
-16
lines changed

2 files changed

+46
-16
lines changed

Diff for: Sources/Observable/ObservableThread.swift

+23-8
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,17 @@ open class ObservableThread: Thread, Observable, ObservableObject {
6868
private var observerRemoveLock = DispatchSemaphore(value: 1)
6969

7070
public func addObserver<TObservationProtocol: AnyObject>(_ observer: TObservationProtocol) {
71-
let lock = observerLock.wait(timeout: DispatchTime.now().advanced(by: DispatchTimeInterval.milliseconds(10))) == .success ? observerLock : observerAddLock
72-
var collection = ObjectIdentifier(lock) == ObjectIdentifier(observerLock) ? observers : observersAddQueue
73-
collection[ObjectIdentifier(observer)] = ObserverContainer(observer: observer, dispatchQueue: OperationQueue.current?.underlyingQueue)
74-
lock.signal()
71+
let observation = ObserverContainer(observer: observer, dispatchQueue: OperationQueue.current?.underlyingQueue)
72+
73+
if observerLock.wait(timeout: DispatchTime.now().advanced(by: DispatchTimeInterval.milliseconds(10))) == .success {
74+
observers[ObjectIdentifier(observer)] = observation
75+
observerLock.signal()
76+
}
77+
else {
78+
observerAddLock.wait()
79+
observersAddQueue[ObjectIdentifier(observer)] = observation
80+
observerAddLock.signal()
81+
}
7582
}
7683

7784
public func removeObserver<TObservationProtocol: AnyObject>(_ observer: TObservationProtocol) {
@@ -105,15 +112,23 @@ open class ObservableThread: Thread, Observable, ObservableObject {
105112
}
106113

107114
self.observerAddLock.wait() // Lock the Add Queue
115+
let observersToAdd = self.observersAddQueue
116+
observersAddQueue.removeAll()
117+
self.observerAddLock.signal() // Release the Add Queue Lock
118+
108119
self.observerRemoveLock.wait() // Lock the Remove Queue
109-
for (id, observation) in observersAddQueue { // Add all of the Queued Observers
120+
let observersToRemove = self.observersRemoveQueue
121+
observersRemoveQueue.removeAll()
122+
self.observerRemoveLock.signal() // Release the Remove Queue Lock
123+
124+
// Add all of the Queued Observers
125+
for (id, observation) in observersToAdd {
110126
observers[id] = observation
111127
}
112-
for (id) in observersRemoveQueue.keys { // Remove all of the Queued Observers
128+
// Remove all of the Queued Observers
129+
for (id) in observersToRemove.keys {
113130
observers.removeValue(forKey: id)
114131
}
115-
self.observerAddLock.signal() // Release the Add Queue Lock
116-
self.observerRemoveLock.signal() // Release the Remove Queue Lock
117132
self.observerLock.signal()
118133
}
119134

Diff for: Sources/Observable/ObservableThreadSafeClass.swift

+23-8
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,17 @@ open class ObservableThreadSafeClass: Observable, ObservableObject {
6868
private var observerRemoveLock = DispatchSemaphore(value: 1)
6969

7070
public func addObserver<TObservationProtocol: AnyObject>(_ observer: TObservationProtocol) {
71-
let lock = observerLock.wait(timeout: DispatchTime.now().advanced(by: DispatchTimeInterval.milliseconds(10))) == .success ? observerLock : observerAddLock
72-
var collection = ObjectIdentifier(lock) == ObjectIdentifier(observerLock) ? observers : observersAddQueue
73-
collection[ObjectIdentifier(observer)] = ObserverContainer(observer: observer, dispatchQueue: OperationQueue.current?.underlyingQueue)
74-
lock.signal()
71+
let observation = ObserverContainer(observer: observer, dispatchQueue: OperationQueue.current?.underlyingQueue)
72+
73+
if observerLock.wait(timeout: DispatchTime.now().advanced(by: DispatchTimeInterval.milliseconds(10))) == .success {
74+
observers[ObjectIdentifier(observer)] = observation
75+
observerLock.signal()
76+
}
77+
else {
78+
observerAddLock.wait()
79+
observersAddQueue[ObjectIdentifier(observer)] = observation
80+
observerAddLock.signal()
81+
}
7582
}
7683

7784
public func removeObserver<TObservationProtocol: AnyObject>(_ observer: TObservationProtocol) {
@@ -105,15 +112,23 @@ open class ObservableThreadSafeClass: Observable, ObservableObject {
105112
}
106113

107114
self.observerAddLock.wait() // Lock the Add Queue
115+
let observersToAdd = self.observersAddQueue
116+
observersAddQueue.removeAll()
117+
self.observerAddLock.signal() // Release the Add Queue Lock
118+
108119
self.observerRemoveLock.wait() // Lock the Remove Queue
109-
for (id, observation) in observersAddQueue { // Add all of the Queued Observers
120+
let observersToRemove = self.observersRemoveQueue
121+
observersRemoveQueue.removeAll()
122+
self.observerRemoveLock.signal() // Release the Remove Queue Lock
123+
124+
// Add all of the Queued Observers
125+
for (id, observation) in observersToAdd {
110126
observers[id] = observation
111127
}
112-
for (id) in observersRemoveQueue.keys { // Remove all of the Queued Observers
128+
// Remove all of the Queued Observers
129+
for (id) in observersToRemove.keys {
113130
observers.removeValue(forKey: id)
114131
}
115-
self.observerAddLock.signal() // Release the Add Queue Lock
116-
self.observerRemoveLock.signal() // Release the Remove Queue Lock
117132
self.observerLock.signal()
118133
}
119134

0 commit comments

Comments
 (0)