UIKit+MapKit项目加载JSON文件地图标注不显示问题求助
问题修正方案
核心问题汇总
- MKMapViewDelegate代理方法名称拼写错误,导致系统无法回调获取标注视图,原代码的
AnnotationView(_:viewFor:)不符合系统代理方法命名规范,不会被触发 - 仅注册了聚类视图,没有注册普通Location标注的视图,也没有在代理方法中返回普通标注的视图实例
- Location类缺少MKAnnotation协议要求的
title属性,标注无法正常显示文本信息 - 普通Location标注没有设置
clusteringIdentifier,无法参与聚类聚合 - 默认地图仅定位到用户当前位置,跨区域的标注不在当前可视范围内,无法被看到
具体修改代码
第一步:修改Location类
import MapKit import UIKit class Location: NSObject, Decodable, Identifiable, MKAnnotation { var id: Int var name: String var latitude: Double var longitude : Double // 新增:MKAnnotation要求的title属性,用于显示标注标题 var title: String? { name } var coordinate: CLLocationCoordinate2D { .init(latitude: latitude, longitude: longitude) } init(id : Int, name : String, latitude : Double, longitude : Double){ self.id = id self.name = name self.longitude = longitude self.latitude = latitude } } struct JsonData : Decodable { let locations : [Location] }
第二步:修改ViewController代码
import CoreLocation import UIKit import MapKit class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate { // 新增:普通标注的复用ID private let locationAnnotationReuseID = "LocationAnnotation" var locations = [Location]() @IBOutlet weak var mapView: MKMapView! let manager = CLLocationManager() override func viewDidLoad() { super.viewDidLoad() mapView.delegate = self // 注册聚类视图 mapView.register(LocationDataMapClusterView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier) // 新增:注册普通标注的视图 mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: locationAnnotationReuseID) } // 修正:代理方法名必须为小写mapView开头才会被系统调用 func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { // 排除用户自身位置标注 guard !annotation.isKind(of: MKUserLocation.self) else { return nil } switch annotation { case is MKClusterAnnotation: return mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier, for: annotation) case let locationAnnotation as Location: let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: locationAnnotationReuseID, for: annotation) as? MKMarkerAnnotationView // 设置聚类ID,开启聚类功能 annotationView?.clusteringIdentifier = locationAnnotationReuseID // 可按需修改标注样式 annotationView?.markerTintColor = .blue annotationView?.canShowCallout = true return annotationView default: return nil } } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) manager.desiredAccuracy = kCLLocationAccuracyBest manager.delegate = self manager.requestWhenInUseAuthorization() manager.startUpdatingLocation() mapView.showsUserLocation = true readFile() mapView.addAnnotations(locations) // 可选新增:加载完标注后自动缩放地图显示所有标注,方便测试 // mapView.showAnnotations(locations, animated: true) } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { if let location = locations.first { manager.stopUpdatingLocation() render(location) } } func render(_ location:CLLocation){ let coordinate = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude) // 放大可视范围,方便查看跨区域标注 let span = MKCoordinateSpan(latitudeDelta: 100, longitudeDelta: 100) let region = MKCoordinateRegion(center: coordinate, span: span) mapView.setRegion(region, animated: true) } public func readFile() { if let url = Bundle.main.url(forResource : "capital", withExtension: "json"), let data = try? Data(contentsOf: url) { let decoder = JSONDecoder() if let jsonData = try? decoder.decode(JsonData.self, from: data){ self.locations = jsonData.locations print(locations) } } } }
验证注意事项
确认capital.json文件已经正确加入项目,并且在Build Phases的Copy Bundle Resources列表中存在,避免读取不到JSON文件。运行项目后缩小地图,即可看到多个标注聚合为聚类视图,放大后聚类拆分为单个标注。
内容的提问来源于stack exchange,提问作者Emmanuel Leicher
相关产品推荐
相关产品推荐

