调用 urlsession 数据后重新加载地图

reload map after calling urlsession data

我是 swift 的新人,我实现了一个带有静态数据的 MapKit,它工作正常,我调用了那个后端引脚数据,它在操场上显示它工作正常,但是地图不显示标记,似乎 mapKit 没有在正确的时间捕获引脚数据,所以我使用 Dispatch.Que 刷新地图但我没有刷新,它显示没有标记

这是我尝试过的:

import UIKit
import MapKit


class myMapViewController: UIViewController, MKMapViewDelegate {
   
    
    var shops = [Shops]()
    var communities = [Community]()
    var cyclists = [Cyclist]()
    var circuits = [Circuit]()
    var BR = BaseUrl.baseUrl
    
    
    @IBOutlet weak var myMap: MKMapView!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.getShops()
        self.getCircuits()
        self.getCyclists()
        self.getCommunities()
        
        //shops.append(Shops(id: 0, title: "Shop1", latitude: 36.553015 , longitude: 10.592774))
        //shops.append(Shops(id: 0, title: "Shop2", latitude: 35.499414 , longitude: 10.824846))
        //communities.append(Community(id: 0, title: "community1", latitude: 37.276943 , longitude: 10.934709 ))
        //communities.append(Community(id: 0, title: "community2", latitude: 35.427828 , longitude: 9.748186 ))
        //circuits.append(Circuit(id: 0, title: "circuit1", latitude: 33.773035 , longitude: 10.857805 ))
        //cyclists.append(Cyclist(id: 0, title: "cyclist1", latitude: 35.785118 , longitude: 10.000871 ))
        createShopsAnnotations(locations: shops)
        createCircuitsAnnotations(locations: circuits)
        createCommunityAnnotations(locations: communities)
        createCyclistsAnnotations(locations: cyclists)
        
    }
    

    
    
    func createShopsAnnotations(locations:[Shops]){
        
        for location in locations {
            let annotations = MKPointAnnotation()
            annotations.title = location.title as? String
            annotations.coordinate = CLLocationCoordinate2D(latitude: location.latitude as! CLLocationDegrees , longitude: location.longitude as! CLLocationDegrees)
            DispatchQueue.main.async {
                self.myMap.addAnnotation(annotations)
            }
            
        }}
        
        
        func createCircuitsAnnotations(locations:[Circuit]){
            
            for location in locations {
                let annotations = MKPointAnnotation()
                annotations.title = location.title as? String
                annotations.coordinate = CLLocationCoordinate2D(latitude: location.latitude as! CLLocationDegrees , longitude: location.longitude as! CLLocationDegrees)
                DispatchQueue.main.async {
                    self.myMap.addAnnotation(annotations)
                }
            }
            
    }

    

    func createCommunityAnnotations(locations:[Community]){
        
        for location in locations {
            
            let annotations = MKPointAnnotation()
            annotations.title = location.title as? String
            annotations.coordinate = CLLocationCoordinate2D(latitude: location.latitude as! CLLocationDegrees , longitude: location.longitude as! CLLocationDegrees)
            DispatchQueue.main.async {
                self.myMap.addAnnotation(annotations)
            }
            
            
        }}
    
    
    
    func createCyclistsAnnotations(locations:[Cyclist]){
        
        for location in locations {
            
            let annotations = MKPointAnnotation()
            annotations.title = location.title as? String
            annotations.coordinate = CLLocationCoordinate2D(latitude: location.latitude as! CLLocationDegrees , longitude: location.longitude as! CLLocationDegrees)
            
            DispatchQueue.main.async {
                self.myMap.addAnnotation(annotations)
            }
            
        }}
    
    
    func getShops(){
    
        //get
      
       guard let url = URL(string: BR+"/shops") else {
       return
       }
       let session = URLSession.shared
       session.dataTask(with: url)  { ( data , response ,error) in
           if let response = response {
               print(response)
           }
           
           if let data = data {
               print(data)
               do
               {
                   let json = try JSONSerialization.jsonObject(with: data, options: [])as! [[String:Any]]
                self.shops.removeAll()
                
                for item in json {
                    let id = item["shop_id"] as! Int
                    let title = item["title"] as! String
                    let latitude = item["latitude"] as! Double
                    let longitude = item["longitude"] as! Double
                    self.shops.append(Shops(id: id, title: title, latitude: latitude , longitude: longitude))
                }
                
                for item in self.shops {
                    print(item.shop_id)
                    print(item.title)
                    print(item.latitude)
                    print(item.longitude)
                }
                  
               }catch{
                   print(error)
               }
           }
           
       }.resume()
        
            
        }
    
    
    
    
    func getCommunities(){
    
        //get
      
       guard let url = URL(string: BR+"/communities") else {
       return
       }
       let session = URLSession.shared
       session.dataTask(with: url)  { ( data , response ,error) in
           if let response = response {
               print(response)
           }
           
           if let data = data {
               print(data)
               do
               {
                   let json = try JSONSerialization.jsonObject(with: data, options: [])as! [[String:Any]]
                self.communities.removeAll()
                
                for item in json {
                    let id = item["community_id"] as! Int
                    let title = item["title"] as! String
                    let latitude = item["latitude"] as! Double
                    let longitude = item["longitude"] as! Double
                    self.communities.append(Community(id: id, title: title, latitude: latitude , longitude: longitude))
                }
                
                for item in self.communities {
                    print(item.community_id)
                    print(item.title)
                    print(item.latitude)
                    print(item.longitude)
                }
                  
               }catch{
                   print(error)
               }
           }
           
       }.resume()
        
            
        }
  
    
    
    
    func getCircuits(){
    
        //get
      
       guard let url = URL(string: BR+"/circuits") else {
       return
       }
       let session = URLSession.shared
       session.dataTask(with: url)  { ( data , response ,error) in
           if let response = response {
               print(response)
           }
           
           if let data = data {
               print(data)
               do
               {
                   let json = try JSONSerialization.jsonObject(with: data, options: [])as! [[String:Any]]
                self.shops.removeAll()
                
                for item in json {
                    let id = item["circuit_id"] as! Int
                    let title = item["title"] as! String
                    let latitude = item["latitude"] as! Double
                    let longitude = item["longitude"] as! Double
                    self.circuits.append(Circuit(id: id, title: title, latitude: latitude , longitude: longitude))
                }
                
                for item in self.circuits {
                    print(item.circuit_id)
                    print(item.title)
                    print(item.latitude)
                    print(item.longitude)
                }
                  
               }catch{
                   print(error)
               }
           }
           
       }.resume()
        
            
        }
    
    
    func getCyclists(){
    
        //get
      
       guard let url = URL(string: BR+"/cyclists") else {
       return
       }
       let session = URLSession.shared
       session.dataTask(with: url)  { ( data , response ,error) in
           if let response = response {
               print(response)
           }
           
           if let data = data {
               print(data)
               do
               {
                   let json = try JSONSerialization.jsonObject(with: data, options: [])as! [[String:Any]]
                self.cyclists.removeAll()
                
                for item in json {
                    let id = item["cyclist_id"] as! Int
                    let title = item["title"] as! String
                    let latitude = item["latitude"] as! Double
                    let longitude = item["longitude"] as! Double
                    self.cyclists.append(Cyclist(id: id, title: title, latitude: latitude , longitude: longitude))
                }
                
                for item in self.cyclists {
                    print(item.cyclist_id)
                    print(item.title)
                    print(item.latitude)
                    print(item.longitude)
                }
                  
               }catch{
                   print(error)
               }
           }
           
       }.resume()
        
            
        }
    
    
    
    
    
    
    
}

我想做的是让 mapkit 在正确的时间捕获图钉数据并刷新它的数据,我认为这是正确显示我的图钉的唯一方法

import UIKit
import MapKit


class myMapViewController: UIViewController, MKMapViewDelegate {
   
    
    var shops = [Shops]()
    var communities = [Community]()
    var cyclists = [Cyclist]()
    var circuits = [Circuit]()
    var BR = BaseUrl.baseUrl
    
    
    @IBOutlet weak var myMap: MKMapView!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
     
            self.myMap.delegate = self
     
       
            
            self.getCircuits()
            self.getCyclists()
            self.getCommunities()
      
        
        
        //shops.append(Shops(id: 0, title: "Shop1", latitude: 36.553015 , longitude: 10.592774))
        //shops.append(Shops(id: 0, title: "Shop2", latitude: 35.499414 , longitude: 10.824846))
        //communities.append(Community(id: 0, title: "community1", latitude: 37.276943 , longitude: 10.934709 ))
        //communities.append(Community(id: 0, title: "community2", latitude: 35.427828 , longitude: 9.748186 ))
        //circuits.append(Circuit(id: 0, title: "circuit1", latitude: 33.773035 , longitude: 10.857805 ))
        //cyclists.append(Cyclist(id: 0, title: "cyclist1", latitude: 35.785118 , longitude: 10.000871 ))
        createShopsAnnotations(locations: shops)
        createCircuitsAnnotations(locations: circuits)
        createCommunityAnnotations(locations: communities)
        createCyclistsAnnotations(locations: cyclists)
        
    }
    

    
    
    func createShopsAnnotations(locations:[Shops]){
        
        for location in locations {
            let annotations = MKPointAnnotation()
            annotations.title = location.title as? String
            annotations.coordinate = CLLocationCoordinate2D(latitude: location.latitude as! CLLocationDegrees , longitude: location.longitude as! CLLocationDegrees)
            DispatchQueue.main.async {
                self.myMap.addAnnotation(annotations)
            }
            
        }}
        
        
        func createCircuitsAnnotations(locations:[Circuit]){
            
            for location in locations {
                let annotations = MKPointAnnotation()
                annotations.title = location.title as? String
                annotations.coordinate = CLLocationCoordinate2D(latitude: location.latitude as! CLLocationDegrees , longitude: location.longitude as! CLLocationDegrees)
                DispatchQueue.main.async {
                    self.myMap.addAnnotation(annotations)
                }
            }
            
    }

    

    func createCommunityAnnotations(locations:[Community]){
        
        for location in locations {
            
            let annotations = MKPointAnnotation()
            annotations.title = location.title as? String
            annotations.coordinate = CLLocationCoordinate2D(latitude: location.latitude as! CLLocationDegrees , longitude: location.longitude as! CLLocationDegrees)
            DispatchQueue.main.async {
                self.myMap.addAnnotation(annotations)
            }
            
            
        }}
    
    
    
    func createCyclistsAnnotations(locations:[Cyclist]){
        
        for location in locations {
            
            let annotations = MKPointAnnotation()
            annotations.title = location.title as? String
            annotations.coordinate = CLLocationCoordinate2D(latitude: location.latitude as! CLLocationDegrees , longitude: location.longitude as! CLLocationDegrees)
            
            DispatchQueue.main.async {
                self.myMap.addAnnotation(annotations)
            }
            
        }}
    
    
    func getShops(){
    
        //get
      
       guard let url = URL(string: BR+"/shops") else {
       return
       }
       let session = URLSession.shared
       session.dataTask(with: url)  { ( data , response ,error) in
           if let response = response {
               print(response)
           }
           
           if let data = data {
               print(data)
               do
               {
                   let json = try JSONSerialization.jsonObject(with: data, options: [])as! [[String:Any]]
                self.shops.removeAll()
                
                for item in json {
                    let id = item["shop_id"] as! Int
                    let title = item["title"] as! String
                    let latitude = item["latitude"] as! Double
                    let longitude = item["longitude"] as! Double
                    self.shops.append(Shops(id: id, title: title, latitude: latitude , longitude: longitude))
                 
                }
                
                for item in self.shops {
                    print(item.shop_id)
                    print(item.title)
                    print(item.latitude)
                    print(item.longitude)
                }
                self.createShopsAnnotations(locations: self.shops)
              
               }catch{
                   print(error)
               }
           }
           
       }.resume()
        
            
        }
    
    
    
    
    func getCommunities(){
    
        //get
      
       guard let url = URL(string: BR+"/communities") else {
       return
       }
       let session = URLSession.shared
       session.dataTask(with: url)  { ( data , response ,error) in
           if let response = response {
               print(response)
           }
           
           if let data = data {
               print(data)
               do
               {
                   let json = try JSONSerialization.jsonObject(with: data, options: [])as! [[String:Any]]
                self.communities.removeAll()
                
                for item in json {
                    let id = item["community_id"] as! Int
                    let title = item["title"] as! String
                    let latitude = item["latitude"] as! Double
                    let longitude = item["longitude"] as! Double
                    self.communities.append(Community(id: id, title: title, latitude: latitude , longitude: longitude))
                }
                
                for item in self.communities {
                    print(item.community_id)
                    print(item.title)
                    print(item.latitude)
                    print(item.longitude)
                }
                self.createCommunityAnnotations(locations: self.communities)
               
               }catch{
                   print(error)
               }
           }
           
       }.resume()
        
            
        }
  
    
    
    
    func getCircuits(){
    
        //get
      
       guard let url = URL(string: BR+"/circuits") else {
       return
       }
       let session = URLSession.shared
       session.dataTask(with: url)  { ( data , response ,error) in
           if let response = response {
               print(response)
           }
           
           if let data = data {
               print(data)
               do
               {
                   let json = try JSONSerialization.jsonObject(with: data, options: [])as! [[String:Any]]
                self.shops.removeAll()
                
                for item in json {
                    let id = item["circuit_id"] as! Int
                    let title = item["title"] as! String
                    let latitude = item["latitude"] as! Double
                    let longitude = item["longitude"] as! Double
                    self.circuits.append(Circuit(id: id, title: title, latitude: latitude , longitude: longitude))
                }
                
                for item in self.circuits {
                    print(item.circuit_id)
                    print(item.title)
                    print(item.latitude)
                    print(item.longitude)
                }
                self.createCircuitsAnnotations(locations: self.circuits)
               
               }catch{
                   print(error)
               }
           }
           
       }.resume()
        
            
        }
    
    
    func getCyclists(){
    
        //get
      
       guard let url = URL(string: BR+"/cyclists") else {
       return
       }
       let session = URLSession.shared
       session.dataTask(with: url)  { ( data , response ,error) in
           if let response = response {
               print(response)
           }
           
           if let data = data {
               print(data)
               do
               {
                   let json = try JSONSerialization.jsonObject(with: data, options: [])as! [[String:Any]]
                self.cyclists.removeAll()
                
                for item in json {
                    let id = item["cyclist_id"] as! Int
                    let title = item["title"] as! String
                    let latitude = item["latitude"] as! Double
                    let longitude = item["longitude"] as! Double
                    self.cyclists.append(Cyclist(id: id, title: title, latitude: latitude , longitude: longitude))
                }
                
                for item in self.cyclists {
                    print(item.cyclist_id)
                    print(item.title)
                    print(item.latitude)
                    print(item.longitude)
                }
                self.createCyclistsAnnotations(locations: self.cyclists)
               }catch{
                   print(error)
               }
           }
           
       }.resume()
        
            
        }
    
    
    
    
    
    
    
}

获取数据是一个异步任务。在问题中,您正在网络请求结束之前更新数据。 将这个问题与这个 以及 Rob 的回答结合起来,您可以将每个 URL 路径分配给地点类型:

enum PlaceType {
    case shop, community, cyclist, circuit
    var urlPath: String {
        switch self { 
        case .shop: return "/shops"
        case .community: return "/communities"
        case .circuit: return "/circuits"
        case .cyclist: return "/cyclists"
    }
}

然后您可以在 for 循环中为每个地点类型获取数据。每次调用该方法获取数据时,您都会传递一个回调以将返回的地点添加到地图中:

@IBOutlet weak var myMap: MKMapView!

override func viewDidLoad() {
    super.viewDidLoad()
        
    for placeType in PlaceType.allCases {
    // Call each get method with a callback
        fetchData(
            for: placeType,
            completion: { [weak self] places in
                guard let self = self else { return }
                self.myMap.addAnnotations(places)                       
            }
        )
    }        
}

fetchData方法只是启动网络请求,完成后调用完成方法:

func fetchData(for placeType: PlaceType, completion: @escaping ([Place]) -> Void) {
    guard let url = URL(string: BR + placeType.urlPath) else { return }
    URLSession.shared.dataTask(with: url)  { ( data , response, error) in
        guard let data = data else { return }
        do {
            let places = try JSONDecoder().decode([Place].self, from: data)
            completion(places) // this is the callback!
        } catch {}
    }.resume()
}

Place class 与 中的相同,但具有解码和编码逻辑:

class Place: NSObject, MKAnnotation, Codable {
    let id: Int
    let type: PlaceType
    let latitude: Double
    let longitude: Double
    dynamic var title: String?
    
    lazy var coordinate: CLLocationCoordinate2D = {
        CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
    }()

    init(id: Int, title: String, latitude: Double, longitude: Double, type: PlaceType) {
        self.id = id
        self.type = type
        self.title = title
        self.latitude = latitude
        self.longitude = longitude

        super.init()
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        // Try to decode each place type id to see which place type the data is for
        var type: PlaceType? = nil
        var tempID: Int? = nil
        PlaceType.allCases.forEach { placeType in
            if let id = try? container.decode(Int.self, forKey: placeType.codingKey) {
                type = placeType
                tempID = id
            }
        }

        guard let decodedType = type, let decodedID = tempID  else {
            let context = DecodingError.Context(
                codingPath: decoder.codingPath,
                debugDescription: "Data does not have data for any of existing place types"
            )
            throw DecodingError.valueNotFound(Place.self, context)
        }
        self.type = decodedType
        self.id = decodedID

        self.title = try container.decode(String.self, forKey: .title)
        self.latitude = try container.decode(Double.self, forKey: .latitude)
        self.longitude = try container.decode(Double.self, forKey: .longitude)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: type.codingKey)
        try container.encode(title, forKey: .title)
        try container.encode(latitude, forKey: .latitude)
        try container.encode(longitude, forKey: .longitude)
    }

    enum CodingKeys: String, CodingKey {
        case shop_id, community_id, circuit_id, cyclist_id
        case title, latitude, longitude
    }
}

您可以看到完整的工作代码here。如果您不明白某些内容,请随时在 Github 中提出有关代码的问题。