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