diff --git a/OTPKit/Sources/OTPKit/Core/Map/OTPMapProvider.swift b/OTPKit/Sources/OTPKit/Core/Map/OTPMapProvider.swift index f1269e1..e5b5911 100644 --- a/OTPKit/Sources/OTPKit/Core/Map/OTPMapProvider.swift +++ b/OTPKit/Sources/OTPKit/Core/Map/OTPMapProvider.swift @@ -13,6 +13,16 @@ import SwiftUI /// Protocol defining the interface for map operations that OTPKit requires. /// Implementers of this protocol can provide their own map view (MKMapView, custom map, etc.) /// while allowing OTPKit to control map content and interactions. +/// +/// Main-actor isolated because every call arrives from a main-actor context — from +/// `MapCoordinator` inside the package, and from host UI code outside it — and because +/// conformances drive UI. Conforming types inherit this isolation, so the members of a +/// custom provider are main-actor isolated too. +/// +/// Stating that here rather than leaving it implicit lets hosts building in the Swift 6 +/// language mode with main-actor default isolation conform directly, instead of opting +/// the conformance out of isolation and hopping back in every method body. +@MainActor public protocol OTPMapProvider: AnyObject { // MARK: - Route Display diff --git a/OTPKit/Tests/SmokeTest.swift b/OTPKit/Tests/SmokeTest.swift index 552e5e0..02f02d2 100644 --- a/OTPKit/Tests/SmokeTest.swift +++ b/OTPKit/Tests/SmokeTest.swift @@ -27,6 +27,9 @@ func testFixturesCreatePlace() { #expect(place.lon == -122.0) } +// `MockMapProvider` conforms to `OTPMapProvider`, which is `@MainActor`, so the +// mock picks up that isolation and the test has to run there too. +@MainActor @Test("MockMapProvider - tracks addRoute calls") func mockMapProviderTracksRouteCalls() { let mockMap = MockMapProvider() diff --git a/README.markdown b/README.markdown index 6792b01..73b29b3 100644 --- a/README.markdown +++ b/README.markdown @@ -125,7 +125,7 @@ Both are Swift actors conforming to `APIService`; you can also implement `APISer - **Transport modes:** pass `enabledTransportModes` to `OTPConfiguration` (defaults to transit, walk, bike, car). Rental modes like `.bikeRental` are opt-in and need an OTP 2.x server with rental data. - **Theme:** pass an `OTPThemeConfiguration` to adjust colors. -- **Map behavior:** implement `OTPMapProvider` to control exactly how routes and stops render on your map. +- **Map behavior:** implement `OTPMapProvider` to control exactly how routes and stops render on your map. The protocol is `@MainActor`, so conformances inherit main-actor isolation — write your provider as main-actor isolated rather than opting the conformance out. ### Localization