reload map after calling urlsession data

匆匆过客 提交于 2021-01-29 15:36:16

问题


I am new in swift , I implemented a MapKit with static data , and it worked fine , and I called after that backend pins data and it showed in the playground that it works fine , but the map is not displaying the markers , it seems that the mapKit do not capture the pins data in the right time , so I used Dispatch.Que to refresh the map but I did not refresh and it is displaying without the markers

here what I have tried :

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()
        
            
        }
    
    
    
    
    
    
    
}

What I am trying to do is to make the mapkit capture the pins data in the right time and refresh it's data, I think it is the only way to display my pins correctly


回答1:


Getting the data is an async task. In the question you are updating the data before the network request has ended. Combining this question with this one Set MapKit pins with different colors and the answer by Rob you could assign each URL path to the place type:

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"
    }
}

and then you could fetch the data in a for loop for each place type. Each time you call the method to fetch data, you'd pass a callback to add the returned places to the map:

@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)                       
            }
        )
    }        
}

The fetchData method just starts the network request and calls the completion method when done:

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()
}

The Place class would be the same one as in the answer from Rob, but with decoding and encoding logic:

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
    }
}

You can see the complete working code here. Feel free to ask questions in Github about the code if you do not understand something.




回答2:


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()
        
            
        }
    
    
    
    
    
    
    
}


来源:https://stackoverflow.com/questions/65647465/reload-map-after-calling-urlsession-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!