admaDIC App Development & IT Solutions

Swift - Networking - ISS Location

by Annett Schwarze | 2025-07-08

The location of the International Space Station can be fetched with a very simple request from api.open-notify.org. With MapKit it is very easy to show it on a map.

The location is fetched from the endpoint `http://api.open-notify.org/iss-now.json` using `URLSession.shared.data(from:)`. To decode the JSON some helper types `ISSNowResponse` etc. can be used.

To display the location on a map use a map view from MapKit: `Map(initialPosition:,content:)`.

Note that the request for the ISS location uses HTTP and the connection is therefore not encrypted. Beginning with iOS 9 non-encrypted connections must be allowed by adding an App Transport Security exception to the Info.plist file:

        
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>NSAppTransportSecurity</key>
 <dict>
  <key>NSExceptionDomains</key>
  <dict>
   <key>api.open-notify.org</key>
   <dict>
    <key>NSExceptionAllowsInsecureHTTPLoads</key>
    <true/>
   </dict>
  </dict>
 </dict>
</dict>
</plist>
    
        
import SwiftUI
import MapKit

class ISSPositionViewModel: ObservableObject {
    enum Err: Error {
        case invalidURL
        case invalidCoordinates

        var localizedDescription: String {
            switch self {
            case .invalidURL: return "Invalid URL"
            case .invalidCoordinates: return "Invalid coordinates"
            }
        }
    }

    /*
     Response format for iss-now from api.open-notify.org:

     {
       "message": "success",
       "timestamp": UNIX_TIME_STAMP,
       "iss_position": {
         "latitude": CURRENT_LATITUDE,
         "longitude": CURRENT_LONGITUDE
       }
     }
     */
    struct ISSNowResponse: Decodable {
        let iss_position: ISSPosition
    }
    struct ISSPosition: Decodable {
        let latitude: String
        let longitude: String
    }

   @Published var coordinate: CLLocationCoordinate2D?
   @Published var isLoading = false
   @Published var errorMessage: String?

    func fetchISSPosition() async {
        await MainActor.run {
            self.isLoading = true
            self.errorMessage = nil
        }
        do {
            let loc = try await fetchISSPosition_impl()
            await MainActor.run {
                self.coordinate = loc
                self.isLoading = false
            }
        } catch {
            await MainActor.run {
                self.errorMessage = error.localizedDescription
                self.isLoading = false
            }
        }
    }

    func fetchISSPosition_impl() async throws -> CLLocationCoordinate2D? {
        guard let url = URL(string: "http://api.open-notify.org/iss-now.json") else {
            throw Err.invalidURL
        }
        let (data, _) = try await URLSession.shared.data(from: url)
        let decoded = try JSONDecoder().decode(ISSNowResponse.self, from: data)
        guard
            let lat = Double(decoded.iss_position.latitude),
            let lon = Double(decoded.iss_position.longitude)
        else {
            throw Err.invalidCoordinates
        }
        return CLLocationCoordinate2D(latitude: lat, longitude: lon)
    }
}

struct SampleISSPositionView: View {
    @ObservedObject private var viewModel = ISSPositionViewModel()

    var body: some View {
        VStack(spacing: 16) {
            if let error = viewModel.errorMessage {
                Text("Error: \(error)").foregroundStyle(.red)
            }
            ZStack {
                Color(white: 0.9)
                if let coordinate = viewModel.coordinate {
                    Map(initialPosition: .region(
                        MKCoordinateRegion(
                            center: coordinate,
                            span: MKCoordinateSpan(latitudeDelta: 180, longitudeDelta: 360)
                        )
                    ), content: {
                        Marker("ISS", coordinate: coordinate)
                            .tint(.red)
                    })
                    .mapStyle(.hybrid)
                } else if viewModel.isLoading {
                    ProgressView("Fetching ...")
                } else {
                    Text("No position available")
                }
            }
            .clipShape(RoundedRectangle(cornerRadius: 24))
        }
        .navigationTitle("ISS Position")
        .navigationBarTitleDisplayMode(.large)
        .task {
            await viewModel.fetchISSPosition()
        }
        .padding()
    }
}

#Preview {
    SampleISSPositionView()
}
    
Swift Networking ISS Location

 

www.admadic.de | webmaster@admadic.de | Legal Notice and Trademarks | Privacy
© 2005-2007 - admaDIC | All Rights Reserved
All other trademarks and/or registered trademarks are the property of their respective owners
Last Change: Tue Jul 8 15:00:40 2025 GMT