Skip to main content

Add live data

Update feature coordinates from a geoJSON source in real time.
import MapboxMaps
import UIKit

final class ViewController: UIViewController {
// Display the current location of the International Space Station (ISS)
private let url = URL(string: "")!
private var mapView: MapView!
private var issTimer: Timer?
private var cancelables = Set<AnyCancelable>()

struct Coordinates: Codable {
let longitude: Double
let latitude: Double

override func viewDidLoad() {

// Set up map and camera
let centerCoordinate = CLLocationCoordinate2D(latitude: 0, longitude: 0)
let camera = CameraOptions(center: centerCoordinate, zoom: 1)
let mapInitOptions = MapInitOptions(cameraOptions: camera, styleURI: .streets)

mapView = MapView(frame: view.bounds, mapInitOptions: mapInitOptions)
mapView.autoresizingMask = [.flexibleHeight, .flexibleWidth]


// Add the live data layer once the map has finished loading.
mapView.mapboxMap.onMapLoaded.observeNext { _ in

}.store(in: &cancelables)

func addStyleLayer() {
// Create an empty geoJSON source to hold location data once
// this information is received from the URL
let source = GeoJSONSource(id: "ISS-source")

var issLayer = SymbolLayer(id: "iss-layer", source:

// Mapbox Streets contains an image named `rocket`. Use that image
// to represent the location of the ISS.
issLayer.iconImage = .constant(.name("rocket"))

do {
try mapView.mapboxMap.addSource(source)
try mapView.mapboxMap.addLayer(issLayer)

// Create a `Timer` that updates the `GeoJSONSource`.
issTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
self?.parseJSON { [weak self] result in
guard let self = self else { return }

switch result {
case .success(let coordinates):
let locationCoordinates = LocationCoordinate2D(latitude: coordinates.latitude, longitude: coordinates.longitude)

// Update geoJSON source to display new location of ISS
let point = Point(locationCoordinates)
let pointFeature = Feature(geometry: point)
self.mapView.mapboxMap.updateGeoJSONSource(withId:, geoJSON: .feature(pointFeature))

// Update camera to follow ISS
let issCamera = CameraOptions(center: locationCoordinates, zoom: 3) issCamera, duration: 1)

case .failure(let error):
print("Error: \(error.localizedDescription)")
} catch {
print("Failed to update the style layer. Error: \(error.localizedDescription)")

// Make a request to the ISS URL, decode the JSON, and return the new coordinates
func parseJSON(completion: @escaping (Result<Coordinates, Error>) -> Void) { { [url] in
let result: Result<Coordinates, Error>
do {
let data = try Data(contentsOf: url)
let coordinates = try JSONDecoder().decode(Coordinates.self, from: data)
result = .success(coordinates)
} catch {
result = .failure(error)
DispatchQueue.main.async {

override func viewDidDisappear(_ animated: Bool) {
issTimer = nil
Was this example helpful?