Swift Concurrency/Isolation Support (MainActor)#49
Open
Swift Concurrency/Isolation Support (MainActor)#49
Conversation
- deinit isolation issue still persists for now, the code in them was commented out
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Swift 6 Strict Concurrency Modernization:
@MainActorisolation across the frameworkBackground
The original RIBs implementation predates Swift's strict concurrency model. At runtime, RIBs has always operated on the main thread — builders build on main, routers route on main, interactors activate and deactivate on main, workers start and stop on main. This was implicit convention, not enforced by the type system.
Swift 6's strict concurrency mode surfaces this as compile-time errors: the compiler sees shared mutable state with no declared isolation and flags it.
This PR is an alternative approach to #45, which addressed the same problem by marking everything
nonisolated. While that silences the compiler, it works against the grain — it declares "this code has no actor isolation" when in practice it has always been main-thread-only. This PR takes the opposite approach: make the implicit explicit by annotating the entire framework with@MainActor.What changed
@MainActoron all core framework types and protocols:Buildable,Builder,Component,EmptyComponent,Dependency,EmptyDependency,InteractorScope,Interactable,Interactor,PresentableInteractor,Presentable,Presenter,RouterLifecycle,RouterScope,Routing,Router,ViewableRouting,ViewableRouter,LaunchRouting,LaunchRouter,ViewControllable,Working,Worker,Workflow,Step,LeakDetector, and all utility extensions (confineTo,disposeOnDeactivate,disposeOnStop,fork,disposeWith).isolated deiniton all classes with non-trivial teardown:Interactor,PresentableInteractor,Router,ViewableRouter, andWorker. These deinits call into@MainActor-isolated code —deactivate(),LeakDetector.instance.expectDeallocate()— which is unsafe ifdeinitruns off the actor.isolated deinitis a Swift 6.2 feature that guarantees deallocation runs on the main actor's executor. Requires Xcode 26.2 / Swift 6.2.Tests: All test classes annotated
@MainActor. Tests exercisingdeinitbehavior markedasyncto accommodate the new isolation semantics.CI: Pinned to
macos-15, Xcode 26.2 explicitly selected (Swift 6.2 required forisolated deinit). Simulator destination pinned to iPhone SE (3rd generation) / iOS 18.5. Working directory updated toExamples/Example1to reflect project structure.Podspec: RxSwift/RxRelay dependency tightened from
~> 6.0to~> 6.9.0.Migration guide (
SWIFT6_STRICT_CONCURRENCY_MIGRATION.md): A step-by-step document covering how to migrate a RIBs-based iOS project to Swift's strict concurrency model — enabling@MainActordefault isolation, resolving common compile errors, and handling the RxSwift@Sendablecaveat.New example app (
RIBsAppExample2): A comprehensive example project illustrating framework patterns — headless RIBs,Worker, presenter separation, deep link workflows withWorkflowand actionable item protocols,ComponentizedBuilderwith dynamic component dependencies (scopedUserSession/CurrentUserService), and async/await bridging to RxSwift viaSingle.create.Compatibility
@MainActor@MainActor@MainActor@MainActor@Sendablecaveat — see below)@MainActor@Sendablecaveat — see below)@MainActor@Sendablecaveat — see below)Summary: All Swift 5 configurations require no changes. Swift 6 requires
@MainActoras the project's default isolation —nonisolateddefault with Swift 6 produces compile errors due to actor isolation mismatches with the now-@MainActor-annotated framework types. Strictness level does not affect the outcome.RxSwift
@Sendablecaveat (Swift 6 +@MainActoronly)Projects using Swift 6 with
@MainActordefault isolation may encounter a runtime crash in RxSwift operators (map,filter,flatMap, etc.) unless closures are annotated@Sendable. This is a known RxSwift limitation tracked in ReactiveX/RxSwift#2639 and is not introduced or caused by these RIBs changes.The alternative is to migrate those pieces to async/await — RIBs now fully supports this at the type system level, and additional async/await convenience utilities are planned as a follow-up to this PR.