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

问题描述

我是 swift 新手,我用静态数据实现了一个 MapKit,它运行良好,我在后端引脚数据之后调用它,它在操场上显示它运行良好,但地图没有显示标记,似乎 mapKit 没有在正确的时间捕获 pin 数据,所以我使用 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,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,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,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,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,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,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 在正确的时间捕获 pin 数据并刷新它的数据,我认为这是正确显示 pin 的唯一方法

解决方法

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

获取数据是一项异步任务。在问题中,您是在网络请求结束之前更新数据。 将此问题与此问题 Set MapKit pins with different colors 和 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,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 类将与 answer from Rob 中的类相同,但具有解码和编码逻辑:

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 中提出有关代码的问题。