Comply with Swift 6 concurrency#728
Draft
stevenzeck wants to merge 52 commits intoreadium:developfrom
Draft
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request migrates the Readium Swift toolkit from Swift 5.10 to Swift 6.0, enabling strict concurrency checking. The migration involves converting classes to actors, adding @MainActor isolation to UI components, making protocols and types Sendable, and updating closures to be @Sendable. The changes are comprehensive and affect the entire codebase including tests.
Changes:
- Migrated swift-tools-version from 5.10 to 6.0 in Package.swift
- Converted service classes (Logger, GeneratedCoverService, PerResourcePositionsService, etc.) to actors for thread safety
- Isolated UI/Navigator components to MainActor to ensure thread-safe UI operations
- Added Sendable conformance to protocols and types throughout the codebase
- Updated closure signatures to be @sendable for concurrency safety
- Changed JSONDictionary and properties from
Anytoany Sendablefor type safety - Refactored resource streaming and caching implementations for concurrency
- Removed deprecated tokenizer implementations (NS and Simple text tokenizers)
Reviewed changes
Copilot reviewed 220 out of 220 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| Package.swift | Updated Swift tools version from 5.10 to 6.0 |
| Tests/**/*.swift | Updated test fixtures and helpers to use any Sendable, changed #file to #filePath, removed deprecated tokenizer tests |
| Sources/Shared/Toolkit/**/*.swift | Added Sendable conformance to core types, protocols, and data structures |
| Sources/Shared/Publication/**/*.swift | Updated JSON dictionary types to any Sendable, added Sendable conformance |
| Sources/Streamer/**/*.swift | Converted services to actors, made factories @sendable |
| Sources/Navigator/**/*.swift | Added @mainactor isolation to UI components and navigators |
| Sources/Navigator/TTS/*.swift | Made TTS components MainActor-isolated, updated delegate callbacks |
| Sources/LCP/**/*.swift | Added Sendable conformance and thread-safety mechanisms |
| Sources/Adapters/**/*.swift | Added @unchecked Sendable and @preconcurrency imports |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
This still needs more testing and a lot of review. But I want to get it out there for visibility. This PR updates swift-build-tools from 5.10 to 6.0. In doing so, strict concurrency is enabled, thus why a lot of changes are needed here.
Swift 6 Strict Concurrency Migration Guide
The vast majority of changes focus on Swift 6 Strict Concurrency adoption. This involves migrating classes to actors, enforcing
@MainActorisolation on UI/Navigator components, addingSendableconformance to protocols and types, and requiring closure callbacks to be@Sendable.This guide has been updated to cover all comprehensive API changes, including the introduction of type-safe JSON handling and asynchronous network delegate methods.
1. Concurrency Isolation Changes
Navigators & UI are now
@MainActorTo ensure thread safety for UI-related operations, the entire Navigator subsystem, input handlers, and view controllers are now isolated to the main thread.
Protocols:
Navigator,VisualNavigator,DecorableNavigator,EPUBNavigatorViewModelDelegate,AudioSessionUser,PreferencesEditor,Configurable,EPUBSpreadViewDelegate,PaginationViewDelegate,AVTTSEngineDelegate,PublicationSpeechSynthesizerDelegateClasses:
AudioNavigator,EPUBFixedSpreadView,EPUBReflowableSpreadView,EPUBSpreadView,PDFDocumentHolder,PDFDocumentView,PDFTapGestureController,AVTTSEngine,PublicationSpeechSynthesizer,NowPlayingInfo,EPUBNavigatorViewController,EditingActionsController,InputObservableViewControllerHelpers:
DirectionalNavigationAdapter,CompletionList,TargetActionInput Events: Initialization methods for
Pointer,KeyEvent,Key,MouseButtons, andKeyModifiersthat take UIKit types (UITouch,UIEvent,UIPress) are now explicitly@MainActor.Impact: You must access these instances and their properties/methods from the Main Actor.
Classes Converted to
actorService classes and resources handling internal mutable state have been converted to
actorto guarantee thread safety.Logger— Previously afinal class. Note:sharedInstanceis now astatic let, and its configuration methods arenonisolatedbut dispatch internally.GeneratedCoverService— Previously afinal classPerResourcePositionsService— Previously afinal classDefaultHTTPClient— Previously afinal classBufferingResource— Previously aclassCachingResource— Previously aclassTailCachingResource— Previously aclassDataResource— Previously aclassHTTPResource— Previously aclassFormatSnifferBlob— Previously aclassEPUBPositionsService— Previously aclassImpact: Synchronous access to properties or methods on these types must now be awaited.
2. Protocol Changes (Sendable Conformance)
The following protocols now inherit from
Sendable. Implementations of these protocols must now be thread-safe.Networking & Data:
HTTPClient,HTTPServer,Resource,Streamer,AssetProtocol,Container,URLConvertible,StreamableServices:
PublicationService,ContentProtection,UserRights,LCPClient,LCPLicenseRepository,LCPPassphraseRepository,LCPAuthenticatingParsing & Format:
PublicationParser,XMLDocument,XMLNode,XMLElement,ResourceFactory,ArchiveOpener,PDFDocument,PDFDocumentFactory,FormatSniffer(includingHintsFormatSnifferandContentFormatSniffer)Logging:
LoggerTypeDelegates:
DefaultHTTPClientDelegateImpact: If you have custom implementations of these protocols (e.g., a custom
HTTPClient), you must ensure they are thread-safe and mark them asSendable(or@unchecked Sendable).3. Closure Signature & Async Changes
Almost all closures used in callbacks, factories, and asynchronous operations are now required to be
@Sendable. Additionally, some closures and delegate methods have becomeasync.HTTP/Networking:
HTTPClient.stream(request:consume:)— Theconsumeclosure is now bothasyncand@Sendable.DefaultHTTPClientDelegate—httpClient(_:request:didReceiveResponse:)andhttpClient(_:request:didFailWithError:)are nowasync.Parsing:
OPDSParser.parseURL(and related v1/v2 parsers) —completionis@Sendable.Publication.Builder.Transform— is@Sendable.Services:
LCPService.acquirePublication—onProgressis@Sendable.TTSEngine.speak—onSpeakRangeis@Sendable.CoverServiceFactory,LocatorServiceFactory,PositionsServiceFactory,ContentProtectionServiceFactory) are now@Sendable.Resources & Tokenizers:
Streamable.stream—consumeis@Sendable.Container.map—transformis@Sendable.ResourceTransformerandTokenizerare now@Sendable.Impact: You cannot capture non-sendable mutable state in these closures anymore, and you must use
awaitwhere new async boundaries have been introduced.4. Type Definition Changes
Type-Safe JSON Parsing (
JSONValue)APIs handling arbitrary JSON data have moved away from
Anyto strictly enforce concurrency safety. The previous approach of usingany Sendablefor JSON has been replaced entirely by a new type-safeJSONValueenum.JSONDictionary.Valueis nowJSONValue.Publicationand OPDS models (Manifest,Locator,Link,Metadata,OPDSAcquisition, etc.) now return[String: JSONValue]for their.jsonproperties instead of[String: Any].UI-Bound Models (
EditingAction)Models meant to be passed across concurrency domains have been stripped of non-
SendableUIKit types.EditingAction.Kindchanged from.custom(UIMenuItem)to.custom(title: String, action: Selector).UIMenuItemgeneration is deferred to a@MainActorproperty.Networking Models
HTTPRequest.userInfo— The value type has changed fromAnyHashabletoany Sendable.CSS Properties
CSS property types in
CSSUserPropertiesandCSSRSPropertieshave changed from concrete generics (e.g.,CSSLength?) to existentials (e.g.,(any CSSLength)?).Utilities
Weak<T>and_Strong<T>— Now utilize an internalNSLockto achieve@unchecked Sendableconformance, making them safe to pass across concurrency boundaries.Finalized Classes
The following classes are now
finaloractor, preventing subclassing:LCPDialogAuthenticationLCPPassphraseAuthenticationReadiumWebPubParser