You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 23:45:03