RxSwift中share(replay:scope:)函数原理及相关代码实现疑问
Great questions diving into the internals of RxSwift's sharing operators! Let's break this down clearly and practically.
1. Differences between replay: 0, replay: 1, and replay > 1 in share(replay:scope:)
First, the replay parameter controls how many historical events new subscribers will receive when they sign up to the shared observable. Here's the breakdown, especially focusing on the .whileConnected scope (the most commonly used default):
- replay: 0
New subscribers only get events emitted after they subscribe—no past events are replayed.
- For
.whileConnectedscope, RxSwift uses the lightweightShareWhileConnectedclass. Since it doesn't need to cache any values, it has minimal memory overhead and snappy performance. - For
.foreverscope, it uses aPublishSubject(which doesn't cache events) wrapped withrefCount().
- replay: 1
New subscribers receive the most recent single event (if the shared observable has already emitted one) plus all future events.
- RxSwift handles this with a dedicated
ShareReplay1WhileConnectedclass. This is a deliberate optimization: instead of using a general-purposeReplaySubject(which maintains an array buffer), this class only stores a single value in a simple variable. This cuts down on memory usage and removes array-related overhead, making it far more efficient for the extremely common "replay last state" use case.
- replay > 1
New subscribers receive the last N events (where N is your replay value) plus future events.
- Here, RxSwift falls back to
ReplaySubject.create(bufferSize: replay)paired withmulticast(makeSubject:)andrefCount(). Since we need to cache multiple values, a dynamic array buffer is necessary, so the general-purposeReplaySubjectis the right tool here.
Why separate replay: 1 from the default case?
It's all about real-world performance. Replaying the last single value is one of the most frequent patterns in RxSwift (e.g., keeping UI elements synced with the latest app state). By building a specialized class for this scenario, RxSwift avoids the unnecessary overhead of managing an array buffer (like ReplaySubject does) and delivers better memory efficiency and faster access to the cached value.
2. Lock Mechanism in the subscribe Function and Observer Connection
Let's walk through what's happening in that subscription code, step by step:
Lock Purpose
The _lock is a mutual exclusion lock (likely an NSLock or similar) designed to prevent race conditions in multi-threaded environments. When multiple threads try to subscribe to the shared observable at the same time, the lock ensures only one thread can modify the observer list or check subscription counts at a time—this avoids bugs like duplicate connection attempts or corrupted observer collections.
Step-by-Step Execution
- Lock Acquisition:
_lock.lock()blocks any other threads from entering this code block until the current thread releases the lock. - Add Observer:
_synchronized_subscribe(observer)adds the new observer to the connection's_observerslist. We capturecountas the number of observers before adding the new one. - Get Disposable: The disposable is retrieved to let the subscriber cancel their subscription later.
- Lock Release:
_lock.unlock()lets other threads proceed with their subscription attempts. - Connect if Needed: If
count == 0, that means this is the first subscriber to the shared observable. We callconnection.connect()to start the source observable emitting events to all subscribed observers.
Handling Blocked Threads
When a thread is blocked waiting for the lock, it simply waits until the lock is released by the thread currently holding it. Once it gains access:
- If the first subscriber already triggered the connection, the new observer is added to the list and will receive all future events (plus any replayed values if applicable).
- If the connection hasn't been triggered yet (a rare edge case), the new thread will check
countand trigger the connection if needed.
This ensures the source observable is only connected once (when the first subscriber arrives), and all subsequent subscribers are safely added to the observer list without race conditions.
内容的提问来源于stack exchange,提问作者Tom

