@@ -83,55 +83,6 @@ import SwiftUI
8383/// }
8484/// ```
8585///
86- /// ### Thread safety
87- ///
88- /// The `Store` class is not thread-safe, and so all interactions with an instance of ``Store``
89- /// (including all of its child stores) must be done on the same thread the store was created on.
90- /// Further, if the store is powering a SwiftUI or UIKit view, as is customary, then all
91- /// interactions must be done on the _main_ thread.
92- ///
93- /// The reason stores are not thread-safe is due to the fact that when an action is sent to a store,
94- /// a reducer is run on the current state, and this process cannot be done from multiple threads.
95- /// It is possible to make this process thread-safe by introducing locks or queues, but this
96- /// introduces new complications:
97- ///
98- /// * If done simply with `DispatchQueue.main.async` you will incur a thread hop even when you are
99- /// already on the main thread. This can lead to unexpected behavior in UIKit and SwiftUI, where
100- /// sometimes you are required to do work synchronously, such as in animation blocks.
101- ///
102- /// * It is possible to create a scheduler that performs its work immediately when on the main
103- /// thread and otherwise uses `DispatchQueue.main.async` (_e.g._, see Combine Schedulers'
104- /// [UIScheduler][uischeduler]).
105- ///
106- /// This introduces a lot more complexity, and should probably not be adopted without having a very
107- /// good reason.
108- ///
109- /// This is why we require all actions be sent from the same thread. This requirement is in the same
110- /// spirit of how `URLSession` and other Apple APIs are designed. Those APIs tend to deliver their
111- /// outputs on whatever thread is most convenient for them, and then it is your responsibility to
112- /// dispatch back to the main queue if that's what you need. The Composable Architecture makes you
113- /// responsible for making sure to send actions on the main thread. If you are using an effect that
114- /// may deliver its output on a non-main thread, you must explicitly perform `.receive(on:)` in
115- /// order to force it back on the main thread.
116- ///
117- /// This approach makes the fewest number of assumptions about how effects are created and
118- /// transformed, and prevents unnecessary thread hops and re-dispatching. It also provides some
119- /// testing benefits. If your effects are not responsible for their own scheduling, then in tests
120- /// all of the effects would run synchronously and immediately. You would not be able to test how
121- /// multiple in-flight effects interleave with each other and affect the state of your application.
122- /// However, by leaving scheduling out of the ``Store`` we get to test these aspects of our effects
123- /// if we so desire, or we can ignore if we prefer. We have that flexibility.
124- ///
125- /// [uischeduler]: https://github.com/pointfreeco/combine-schedulers/blob/main/Sources/CombineSchedulers/UIScheduler.swift
126- ///
127- /// #### Thread safety checks
128- ///
129- /// The store performs some basic thread safety checks in order to help catch mistakes. Stores
130- /// constructed via the initializer ``init(initialState:reducer:withDependencies:)`` are assumed
131- /// to run only on the main thread, and so a check is executed immediately to make sure that is the
132- /// case. Further, all actions sent to the store and all scopes (see ``scope(state:action:)-90255``)
133- /// of the store are also checked to make sure that work is performed on the main thread.
134- ///
13586/// ### ObservableObject conformance
13687///
13788/// The store conforms to `ObservableObject` but is _not_ observable via the `@ObservedObject`
0 commit comments