Skip to content

Commit b72eda3

Browse files
committed
fix: Drop @mainactor and Sendable requirement for scheduler
1 parent a1d2c62 commit b72eda3

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

Demo Project/ResponsiveTextFieldDemo/ContentView.swift

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct ContentView: View {
9393
configuration: .combine(.password, .lastOfChain),
9494
onFirstResponderStateChanged: FirstResponderStateChangeHandler
9595
.updates($isPasswordFirstResponder)
96+
.receive(on: RunLoop.main)
9697
.animation(),
9798
handleReturn: { passwordResponderDemand = .shouldResignFirstResponder },
9899
handleDelete: {

Sources/ResponsiveTextField/ResponsiveTextField.swift

+17-3
Original file line numberDiff line numberDiff line change
@@ -254,18 +254,32 @@ public struct FirstResponderStateChangeHandler: Sendable {
254254
/// cycle completes using this method. You can pass in any suitable scheduler, such as `RunLoop.main` or
255255
/// `DispatchQueue.main`.
256256
///
257-
public func receive<S: Scheduler>(on scheduler: S, options: S.SchedulerOptions? = nil) -> Self
258-
where S: Sendable, S.SchedulerOptions: Sendable {
257+
public func receive<S: Scheduler>(on scheduler: S, options: S.SchedulerOptions? = nil) -> Self {
258+
let _scheduler = _Scheduler(scheduler: scheduler, options: options)
259259
return .init(
260260
handleStateChange: { isFirstResponder in
261-
scheduler.schedule(options: options) {
261+
_scheduler.schedule {
262262
self.handleStateChange(isFirstResponder)
263263
}
264264
},
265265
canBecomeFirstResponder: canBecomeFirstResponder,
266266
canResignFirstResponder: canResignFirstResponder
267267
)
268268
}
269+
270+
// Currently whilst DispatchQueue is unchecked sendable, RunLoop is not, and neither are
271+
// their scheduler options so we need to wrap it in a small unchecked sendable value to
272+
// cross the sendable boundary.
273+
private struct _Scheduler<S: Scheduler>: @unchecked Sendable {
274+
let scheduler: S
275+
let options: S.SchedulerOptions?
276+
277+
func schedule(_ action: @escaping @Sendable @MainActor () -> Void) {
278+
scheduler.schedule(options: options) {
279+
Task { @MainActor in action() }
280+
}
281+
}
282+
}
269283
}
270284

271285
extension FirstResponderStateChangeHandler {

0 commit comments

Comments
 (0)