Skip to content

Commit 0e7606d

Browse files
Cramsdenih-codes
andauthored
Refactor FXIOS-13944 [Swift 6] Isolate new state and subsequently a lot of redux to the main thread (#30301)
* isolate new state and subsequently a lot of redux to the main thread * fix tests * Swiftlint fix. * Addressed some PR feedback. * Fix unit tests. * Isolate store to the main actor in entirety * remove nonisolated for ui objc method --------- Co-authored-by: ih-codes <[email protected]>
1 parent cf2e58a commit 0e7606d

File tree

18 files changed

+183
-117
lines changed

18 files changed

+183
-117
lines changed

BrowserKit/Sources/Redux/DispatchStore.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@ public protocol DispatchStore {
1414
public protocol DefaultDispatchStore<State>: DispatchStore where State: StateType {
1515
associatedtype State
1616

17+
@MainActor
1718
var state: State { get }
1819

20+
@MainActor
1921
func subscribe<S: StoreSubscriber>(_ subscriber: S) where S.SubscriberStateType == State
22+
@MainActor
2023
func subscribe<SubState, S: StoreSubscriber>(
2124
_ subscriber: S,
2225
transform: ((Subscription<State>) -> Subscription<SubState>)?
2326
) where S.SubscriberStateType == SubState
27+
@MainActor
2428
func unsubscribe<S: StoreSubscriber>(_ subscriber: S) where S.SubscriberStateType == State
29+
@MainActor
2530
func unsubscribe(_ subscriber: any StoreSubscriber)
2631
}

BrowserKit/Sources/Redux/Store.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Common
88
/// Stores your entire app state in the form of a single data structure.
99
/// This state can only be modified by dispatching Actions to the store.
1010
/// Whenever the state of the store changes, the store will notify all store subscriber.
11+
@MainActor
1112
public final class Store<State: StateType & Sendable>: DefaultDispatchStore {
1213
typealias SubscriptionType = SubscriptionWrapper<State>
1314

@@ -32,6 +33,7 @@ public final class Store<State: StateType & Sendable>: DefaultDispatchStore {
3233
private var actionQueue: [Action] = []
3334
private var isProcessingActions = false
3435

36+
@MainActor
3537
public init(state: State,
3638
reducer: @escaping Reducer<State>,
3739
middlewares: [Middleware<State>] = [],
@@ -84,15 +86,13 @@ public final class Store<State: StateType & Sendable>: DefaultDispatchStore {
8486
}
8587
}
8688

87-
@MainActor
8889
public func dispatch(_ action: Action) {
8990
MainActor.assertIsolated("Expected to be called only on main actor.")
9091
logger.log("Dispatched action: \(action.debugDescription)", level: .info, category: .redux)
9192
actionQueue.append(action)
9293
processQueuedActions()
9394
}
9495

95-
@MainActor
9696
private func processQueuedActions() {
9797
guard !isProcessingActions else { return }
9898
isProcessingActions = true
@@ -103,7 +103,6 @@ public final class Store<State: StateType & Sendable>: DefaultDispatchStore {
103103
isProcessingActions = false
104104
}
105105

106-
@MainActor
107106
private func executeAction(_ action: Action) {
108107
// Each active screen state is given an opportunity to be reduced using the dispatched action
109108
// (Note: this is true even if the action's UUID differs from the screen's window's UUID).

BrowserKit/Sources/Redux/StoreSubscriber.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import Foundation
66

77
public protocol AnyStoreSubscriber: AnyObject {
8+
@MainActor
89
func subscribeToRedux()
10+
@MainActor
911
func newState(state: Any)
1012
}
1113

@@ -17,10 +19,12 @@ public protocol StoreSubscriber: AnyStoreSubscriber {
1719

1820
/// Updates the subscriber with a new State for its screen state type.
1921
/// - Parameter state: the changed screen state.
22+
@MainActor
2023
func newState(state: SubscriberStateType)
2124
}
2225

2326
extension StoreSubscriber {
27+
@MainActor
2428
public func newState(state: Any) {
2529
if let typedState = state as? SubscriberStateType {
2630
newState(state: typedState)

BrowserKit/Sources/Redux/Subscription.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
import Foundation
66

7-
final class SubscriptionWrapper<State>: Hashable {
7+
@MainActor
8+
final class SubscriptionWrapper<State>: @MainActor Hashable {
89
private let originalSubscription: Subscription<State>
910
weak var subscriber: AnyStoreSubscriber?
1011
private let objectIdentifier: ObjectIdentifier
@@ -41,12 +42,13 @@ final class SubscriptionWrapper<State>: Hashable {
4142
}
4243
}
4344

45+
@MainActor
4446
public final class Subscription<State> {
45-
public var observer: ((State?, State) -> Void)?
47+
public var observer: (@MainActor (State?, State) -> Void)?
4648

4749
init() {}
4850

49-
public init(sink: @escaping (@escaping (State?, State) -> Void) -> Void) {
51+
init(sink: @escaping (@MainActor @escaping (State?, State) -> Void) -> Void) {
5052
sink { old, new in
5153
self.newValues(oldState: old, newState: new)
5254
}

firefox-ios/Client/Frontend/Browser/Toolbars/AddressBarPanGestureHandler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ final class AddressBarPanGestureHandler: NSObject, StoreSubscriber {
106106
}
107107

108108
// MARK: - Redux
109-
nonisolated func subscribeToRedux() {
109+
func subscribeToRedux() {
110110
let uuid = windowUUID
111111
store.subscribe(self, transform: {
112112
$0.select({ appState in

firefox-ios/Client/Frontend/Browser/Toolbars/Models/AddressToolbarContainerModel.swift

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ final class AddressToolbarContainerModel: Equatable {
254254
return searchEnginesManager.queryForSearchURL(searchURL)
255255
}
256256

257+
@MainActor
257258
private static func mapActions(_ actions: [ToolbarActionConfiguration],
258259
isShowingTopTabs: Bool,
259260
windowUUID: UUID) -> [ToolbarElement] {
@@ -285,42 +286,39 @@ final class AddressToolbarContainerModel: Equatable {
285286
}
286287
}
287288

289+
@MainActor
288290
private static func getA11yCustomAction(action: ToolbarActionConfiguration, windowUUID: UUID) -> (() -> Void)? {
289291
return action.a11yCustomActionName != nil ? {
290-
ensureMainThread {
291-
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
292-
windowUUID: windowUUID,
293-
actionType: ToolbarMiddlewareActionType.customA11yAction)
294-
store.dispatch(action)
295-
}
292+
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
293+
windowUUID: windowUUID,
294+
actionType: ToolbarMiddlewareActionType.customA11yAction)
295+
store.dispatch(action)
296296
} : nil
297297
}
298298

299+
@MainActor
299300
private static func getOnSelected(action: ToolbarActionConfiguration, windowUUID: UUID) -> ((UIButton) -> Void)? {
300301
return { button in
301-
ensureMainThread {
302-
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
303-
buttonTapped: button,
304-
gestureType: .tap,
305-
windowUUID: windowUUID,
306-
actionType: ToolbarMiddlewareActionType.didTapButton)
307-
store.dispatch(action)
308-
}
302+
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
303+
buttonTapped: button,
304+
gestureType: .tap,
305+
windowUUID: windowUUID,
306+
actionType: ToolbarMiddlewareActionType.didTapButton)
307+
store.dispatch(action)
309308
}
310309
}
311310

311+
@MainActor
312312
private static func getOnLongPress(action: ToolbarActionConfiguration,
313313
windowUUID: UUID,
314314
isShowingTopTabs: Bool) -> ((UIButton) -> Void)? {
315315
return action.canPerformLongPressAction(isShowingTopTabs: isShowingTopTabs) ? { button in
316-
ensureMainThread {
317-
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
318-
buttonTapped: button,
319-
gestureType: .longPress,
320-
windowUUID: windowUUID,
321-
actionType: ToolbarMiddlewareActionType.didTapButton)
322-
store.dispatch(action)
323-
}
316+
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
317+
buttonTapped: button,
318+
gestureType: .longPress,
319+
windowUUID: windowUUID,
320+
actionType: ToolbarMiddlewareActionType.didTapButton)
321+
store.dispatch(action)
324322
} : nil
325323
}
326324

firefox-ios/Client/Frontend/Browser/Toolbars/Models/NavigationToolbarContainerModel.swift

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct NavigationToolbarContainerModel: Equatable {
1818
isTranslucencyEnabled: isTranslucent)
1919
}
2020

21+
@MainActor
2122
init(state: ToolbarState, windowUUID: WindowUUID) {
2223
self.displayBorder = state.navigationToolbar.displayBorder
2324
self.canShowNavigationHint = state.canShowNavigationHint
@@ -51,42 +52,39 @@ struct NavigationToolbarContainerModel: Equatable {
5152
self.windowUUID = windowUUID
5253
}
5354

55+
@MainActor
5456
private static func getA11yCustomAction(action: ToolbarActionConfiguration, windowUUID: WindowUUID) -> (() -> Void)? {
5557
return action.a11yCustomActionName != nil ? {
56-
ensureMainThread {
57-
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
58-
windowUUID: windowUUID,
59-
actionType: ToolbarMiddlewareActionType.customA11yAction)
60-
store.dispatch(action)
61-
}
58+
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
59+
windowUUID: windowUUID,
60+
actionType: ToolbarMiddlewareActionType.customA11yAction)
61+
store.dispatch(action)
6262
} : nil
6363
}
6464

65+
@MainActor
6566
private static func getOnSelected(action: ToolbarActionConfiguration, windowUUID: WindowUUID) -> ((UIButton) -> Void)? {
6667
return { button in
67-
ensureMainThread {
68-
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
69-
buttonTapped: button,
70-
gestureType: .tap,
71-
windowUUID: windowUUID,
72-
actionType: ToolbarMiddlewareActionType.didTapButton)
73-
store.dispatch(action)
74-
}
68+
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
69+
buttonTapped: button,
70+
gestureType: .tap,
71+
windowUUID: windowUUID,
72+
actionType: ToolbarMiddlewareActionType.didTapButton)
73+
store.dispatch(action)
7574
}
7675
}
7776

77+
@MainActor
7878
private static func getOnLongPress(action: ToolbarActionConfiguration,
7979
state: ToolbarState,
8080
windowUUID: WindowUUID) -> ((UIButton) -> Void)? {
8181
return action.canPerformLongPressAction(isShowingTopTabs: state.isShowingTopTabs) ? { button in
82-
ensureMainThread {
83-
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
84-
buttonTapped: button,
85-
gestureType: .longPress,
86-
windowUUID: windowUUID,
87-
actionType: ToolbarMiddlewareActionType.didTapButton)
88-
store.dispatch(action)
89-
}
82+
let action = ToolbarMiddlewareAction(buttonType: action.actionType,
83+
buttonTapped: button,
84+
gestureType: .longPress,
85+
windowUUID: windowUUID,
86+
actionType: ToolbarMiddlewareActionType.didTapButton)
87+
store.dispatch(action)
9088
} : nil
9189
}
9290
}

0 commit comments

Comments
 (0)