Skip to Content
ExamplesDisplay a weather map

MapsGL iOS - Display a weather map

Create a map controller and stack two weather layers on the map.

Display a weather map

The full file is DisplayAWeatherMapExample.swift in the demo app . Every example builds on the demo’s own scaffolding types  — ExampleMapView and friends — which wrap the map view and its overlay chrome so each file can stay focused on one API.

DisplayAWeatherMapExample.swift
// // DisplayAWeatherMapExample.swift // Demo // import Combine import CoreLocation import MapsGLMaps import SwiftUI /// The smallest useful MapsGL integration, written out in full. /// /// Every other SwiftUI example is built on ``ExampleMapView``, which owns the map, /// the controller and the Combine subscriptions so that an example file contains /// only the API it is demonstrating. This one does that work itself, so there is /// one place to read what the scaffold does on the others' behalf. /// ``UIKitIntegrationExample`` is the same integration without SwiftUI. /// /// Three things an integration has to get right are visible here: /// /// - **Something has to own the controller and the subscriptions.** SwiftUI /// re-evaluates `body` freely; the controller must survive that. A `StateObject` /// does, which is why the wiring lives in ``WeatherMapModel`` and not in `body`. /// - **Weather layers are added after `onLoad`.** The controller exists as soon as /// the map view does, but the map's style does not, and a layer added against a /// style that has not loaded yet is dropped. /// - **The map-ready callback can run more than once** for the same map, so /// attaching guards against wiring it twice. /// - **The controller has to be let go of.** It owns the map, so the model detaches /// it when the screen goes away, and its observers hold it weakly. /// /// `addWeatherLayer(for:beforeId:)` builds the layer's source, paint, legend and /// inspector formatting from the weather spec, so one call per layer is enough. /// Layers stack in the order they are added — radar first, then alert outlines over /// it — and `beforeId` keeps the base map's place labels above both. struct DisplayAWeatherMapExample: View { @StateObject private var model = WeatherMapModel() /// Follows the system appearance, so the basemap restyles when it changes. @Environment(\.colorScheme) private var colorScheme var body: some View { DemoSwiftUIMapView( colorScheme: colorScheme, initialCenter: CLLocationCoordinate2D(latitude: 40, longitude: -85.5), initialZoom: 3, // The mapping library's own ornaments move rather than the demo's // chrome: the scale bar drops below the floating back button, and the // logo and attribution lift far enough off the bottom edge to stay // legible in a documentation screenshot. ornamentInsets: .init( top: ExampleChrome.controlsTopInset, bottom: ExampleCaptureMode.hidesControls ? XWSpace.x4 : 0 ) ) { mapController, _ in model.attach(mapController) } .ignoresSafeArea() } } /// Owns the map controller and the Combine subscriptions for /// ``DisplayAWeatherMapExample``. /// /// Held as a `StateObject` so that both outlive any one evaluation of the view's /// body. Releasing the bag cancels the observers, so its lifetime is the /// observation's lifetime. @MainActor final class WeatherMapModel: ObservableObject { private var mapController: DemoMapController? private var subscriptions: Set<AnyCancellable> = [] /// Takes the controller back off the map when this model is released. private var detacher: ExampleMapDetacher? /// Wires up a controller the map view has just handed over. Safe to call again /// for a map that is already attached. func attach(_ mapController: DemoMapController) { guard self.mapController == nil else { return } self.mapController = mapController self.detacher = ExampleMapDetacher(mapController) mapController.onLoad.observe { [weak self, weak mapController] _ in guard let self, let mapController else { return } self.addWeatherLayers(to: mapController) }.store(in: &subscriptions) } private func addWeatherLayers(to mapController: DemoMapController) { for code in [WeatherService.LayerCode.radar, .alertsOutline] { do { let beforeId = DemoMapProvider.weatherLayerInsertBeforeId( for: mapController, layerCode: code ) try mapController.addWeatherLayer(for: code, beforeId: beforeId) } catch { print("Failed to add \(code.rawValue): \(error)") } } } } #Preview { DisplayAWeatherMapExample() }
© 2026 Xweather (opens in a new tab)Terms of Service (opens in a new tab)Privacy Policy (opens in a new tab)