skip to Main Content

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

2

Answers


  1. Chosen as BEST ANSWER
    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()
            
                
            }
        
        
        
        
        
        
        
    }
    

  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search