Я пытаюсь создать карту Mapbox и загрузить список стран из CSV-файла. Аннотации добавляются из этой строки, которая работает. Однако мне нужно, чтобы эта функция выполнялась только один раз, иначе это вызовет проблемы с производительностью. Независимо от того, как я меняю строку на другое место, это не работает.
Я новичок в Swift, и буду очень благодарен за любую помощь.
//
// ContentView.swift
//
import SwiftUI
import MapboxMaps
import CoreLocation
import FlagKit
struct ContentView: View {
@StateObject private var viewModel = CountryViewModel()
@StateObject private var locationManager = LocationManager()
@State private var isPanelExpanded = false
@State private var selectedCountry: Country?
@State private var countryInfo: String = ""
var body: some View {
ZStack {
MapViewRepresentable(countries: viewModel.countries, userLocation: locationManager.location, onCountryTapped: { country, info in
selectedCountry = country
countryInfo = info
isPanelExpanded = true
})
.ignoresSafeArea()
.onAppear {
viewModel.loadCountries()
locationManager.requestLocation()
}
VStack {
Spacer()
BottomPanelView(isExpanded: $isPanelExpanded, country: $selectedCountry, countryInfo: $countryInfo)
.frame(height: isPanelExpanded ? 300 : 100)
.transition(.move(edge: .bottom))
}
}
}
}
struct MapViewRepresentable: UIViewRepresentable {
let countries: [Country]
let userLocation: CLLocationCoordinate2D?
let onCountryTapped: (Country, String) -> Void
private func fetchCountryInfo(for country: Country, completion: @escaping (Result) -> Void) {
let countryName = country.name.replacingOccurrences(of: " ", with: "_")
let urlString = "https://en.wikipedia.org/api/rest_v1/page/summary/\(countryName)"
guard let url = URL(string: urlString) else {
completion(.failure(NSError(domain: "Invalid URL", code: 0, userInfo: nil)))
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
guard let data = data else {
completion(.failure(NSError(domain: "No data", code: 0, userInfo: nil)))
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let extract = json["extract"] as? String {
print("Fetched content: \(extract)") // Debugging print statement
completion(.success(extract))
} else {
completion(.failure(NSError(domain: "Invalid JSON", code: 0, userInfo: nil)))
}
} catch {
completion(.failure(error))
}
}
task.resume()
}
static let defaultLocation = CLLocationCoordinate2D(latitude: 22.3193, longitude: 114.1694)
func makeUIView(context: Context) -> MapboxMaps.MapView {
let options = MapInitOptions(cameraOptions: CameraOptions(center: userLocation ?? MapViewRepresentable.defaultLocation, zoom: 10))
let mapView = MapboxMaps.MapView(frame: .zero, mapInitOptions: options)
mapView.gestures.delegate = context.coordinator
context.coordinator.mapView = mapView
return mapView
}
func updateUIView(_ uiView: MapboxMaps.MapView, context: Context) {
addCountryAnnotations(to: uiView, context: context)
}
private func addCountryAnnotations(to mapView: MapboxMaps.MapView, context: Context) {
var annotations: [PointAnnotation] = []
for country in countries {
var annotation = PointAnnotation(coordinate: country.coordinate)
if let flagImage = country.flagImage {
annotation.image = .init(image: flagImage.resized(to: CGSize(width: 30, height: 20)), name: country.code)
}
annotation.iconAnchor = .bottom
annotations.append(annotation)
}
let annotationManager = mapView.annotations.makePointAnnotationManager()
annotationManager.annotations = annotations
annotationManager.delegate = context.coordinator
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, AnnotationInteractionDelegate, GestureManagerDelegate {
var parent: MapViewRepresentable
var mapView: MapboxMaps.MapView?
init(_ parent: MapViewRepresentable) {
self.parent = parent
}
func annotationManager(_ manager: AnnotationManager, didDetectTappedAnnotations annotations: [Annotation]) {
guard let annotation = annotations.first as? PointAnnotation, let countryName = annotation.textField else { return }
if let country = parent.countries.first(where: { $0.name == countryName }) {
parent.fetchCountryInfo(for: country) { result in
switch result {
case .success(let info):
DispatchQueue.main.async {
self.parent.onCountryTapped(country, info)
}
case .failure(let error):
print("Failed to fetch country info: \(error.localizedDescription)")
}
}
flyToCountry(country)
}
}
private func flyToCountry(_ country: Country) {
guard let mapView = mapView else { return }
let cameraOptions = CameraOptions(center: country.coordinate, zoom: 10, bearing: 0, pitch: 0)
mapView.camera.fly(to: cameraOptions, duration: 2.0)
}
// Implement required methods for GestureManagerDelegate
func gestureManager(_ gestureManager: GestureManager, didBegin gestureType: GestureType) {}
func gestureManager(_ gestureManager: GestureManager, didEnd gestureType: GestureType, willAnimate: Bool) {}
func gestureManager(_ gestureManager: GestureManager, didEndAnimatingFor gestureType: GestureType) {}
}
}
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
@Published var location: CLLocationCoordinate2D?
override init() {
super.init()
locationManager.delegate = self
}
func requestLocation() {
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
location = locations.first?.coordinate
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Failed to get user location: \(error.localizedDescription)")
}
}
extension UIImage {
func resized(to size: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
draw(in: CGRect(origin: .zero, size: size))
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resizedImage!
}
}
Я следовал официальной документации здесь, однако она не дает примера того, как взаимодействовать с настройкой карты и использованием UIKit. Я предполагаю, что это сильно устарело. https://docs.mapbox.com/ios/maps/guides ... notations/
Я пытаюсь создать карту Mapbox и загрузить список стран из CSV-файла. Аннотации добавляются из этой строки, которая работает. Однако мне нужно, чтобы эта функция выполнялась только один раз, иначе это вызовет проблемы с производительностью. Независимо от того, как я меняю строку на другое место, это не работает. Я новичок в Swift, и буду очень благодарен за любую помощь. [code]func updateUIView(_ uiView: MapboxMaps.MapView, context: Context) { addCountryAnnotations(to: uiView, context: context) } [/code] Это мой полный код. [code]// // ContentView.swift //
for country in countries { var annotation = PointAnnotation(coordinate: country.coordinate) if let flagImage = country.flagImage { annotation.image = .init(image: flagImage.resized(to: CGSize(width: 30, height: 20)), name: country.code) } annotation.iconAnchor = .bottom annotations.append(annotation) }
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { private let locationManager = CLLocationManager() @Published var location: CLLocationCoordinate2D?
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("Failed to get user location: \(error.localizedDescription)") } }
extension UIImage { func resized(to size: CGSize) -> UIImage { UIGraphicsBeginImageContextWithOptions(size, false, 0.0) draw(in: CGRect(origin: .zero, size: size)) let resizedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return resizedImage! } } [/code] Я следовал официальной документации здесь, однако она не дает примера того, как взаимодействовать с настройкой карты и использованием UIKit. Я предполагаю, что это сильно устарело. https://docs.mapbox.com/ios/maps/guides/markers-and-annotations/annotations/